Browse Source

moving image update into image view

Johann ELSASS 5 years ago
parent
commit
46078fdf0a

+ 34 - 1
lazpaint/lazpaintinstance.pas

@@ -108,6 +108,7 @@ type
     FInRunScript: boolean;
     FInRunScript: boolean;
     FScriptTempFileNames: TStringList;
     FScriptTempFileNames: TStringList;
     FInCommandLine: boolean;
     FInCommandLine: boolean;
+    FUpdateStackOnTimer: boolean;
 
 
     function GetIcons(ASize: integer): TImageList; override;
     function GetIcons(ASize: integer): TImageList; override;
     function GetToolBoxWindowPopup: TPopupMenu; override;
     function GetToolBoxWindowPopup: TPopupMenu; override;
@@ -143,6 +144,8 @@ type
     function GetImage: TLazPaintImage; override;
     function GetImage: TLazPaintImage; override;
     function GetImageAction: TImageActions; override;
     function GetImageAction: TImageActions; override;
     function GetToolManager: TToolManager; override;
     function GetToolManager: TToolManager; override;
+    function GetUpdateStackOnTimer: boolean; override;
+    procedure SetUpdateStackOnTimer(AValue: boolean); override;
     procedure CreateLayerStack;
     procedure CreateLayerStack;
     procedure CreateToolBox;
     procedure CreateToolBox;
     procedure FormsNeeded;
     procedure FormsNeeded;
@@ -202,6 +205,7 @@ type
     destructor Destroy; override;
     destructor Destroy; override;
     procedure NotifyImageChange(RepaintNow: boolean; ARect: TRect); override;
     procedure NotifyImageChange(RepaintNow: boolean; ARect: TRect); override;
     procedure NotifyImageChangeCompletely(RepaintNow: boolean); override;
     procedure NotifyImageChangeCompletely(RepaintNow: boolean); override;
+    procedure NotifyImagePaint; override;
     function TryOpenFileUTF8(filename: string; skipDialogIfSingleImage: boolean = false): boolean; override;
     function TryOpenFileUTF8(filename: string; skipDialogIfSingleImage: boolean = false): boolean; override;
     function ExecuteFilter(filter: TPictureFilter; skipDialog: boolean = false): TScriptResult; override;
     function ExecuteFilter(filter: TPictureFilter; skipDialog: boolean = false): TScriptResult; override;
     function RunScript(AFilename: string): boolean; override;
     function RunScript(AFilename: string): boolean; override;
@@ -247,6 +251,8 @@ type
     property MainFormVisible: boolean read GetMainFormVisible;
     property MainFormVisible: boolean read GetMainFormVisible;
     procedure NotifyStackChange; override;
     procedure NotifyStackChange; override;
     procedure ScrollLayerStackOnItem(AIndex: integer; ADelayedUpdate: boolean = true); override;
     procedure ScrollLayerStackOnItem(AIndex: integer; ADelayedUpdate: boolean = true); override;
+    procedure InvalidateLayerStack; override;
+    procedure UpdateLayerStackOnTimer; override;
     function MakeNewBitmapReplacement(AWidth, AHeight: integer; AColor: TBGRAPixel): TBGRABitmap; override;
     function MakeNewBitmapReplacement(AWidth, AHeight: integer; AColor: TBGRAPixel): TBGRABitmap; override;
     procedure ChooseTool(Tool : TPaintToolType); override;
     procedure ChooseTool(Tool : TPaintToolType); override;
     function OpenImage (FileName: string; AddToRecent: Boolean= True): boolean; override;
     function OpenImage (FileName: string; AddToRecent: Boolean= True): boolean; override;
@@ -497,6 +503,16 @@ begin
   Result:= FToolManager;
   Result:= FToolManager;
 end;
 end;
 
 
+function TLazPaintInstance.GetUpdateStackOnTimer: boolean;
+begin
+  result := FUpdateStackOnTimer;
+end;
+
+procedure TLazPaintInstance.SetUpdateStackOnTimer(AValue: boolean);
+begin
+  FUpdateStackOnTimer := AValue;
+end;
+
 procedure TLazPaintInstance.CreateLayerStack;
 procedure TLazPaintInstance.CreateLayerStack;
 var
 var
   defaultZoom: Single;
   defaultZoom: Single;
@@ -1580,6 +1596,12 @@ begin
   If RepaintNow then FMain.Update;
   If RepaintNow then FMain.Update;
 end;
 end;
 
 
+procedure TLazPaintInstance.NotifyImagePaint;
+begin
+  if Assigned(FMain) then
+    FMain.NotifyImagePaint;
+end;
+
 function TLazPaintInstance.TryOpenFileUTF8(filename: string; skipDialogIfSingleImage: boolean): boolean;
 function TLazPaintInstance.TryOpenFileUTF8(filename: string; skipDialogIfSingleImage: boolean): boolean;
 begin
 begin
   FormsNeeded;
   FormsNeeded;
@@ -1778,10 +1800,21 @@ begin
   begin
   begin
     if not Assigned(FMain) then ADelayedUpdate:= false;
     if not Assigned(FMain) then ADelayedUpdate:= false;
     FLayerStack.ScrollToItem(AIndex, not ADelayedUpdate);
     FLayerStack.ScrollToItem(AIndex, not ADelayedUpdate);
-    if ADelayedUpdate then FMain.UpdateStackOnTimer := true;
+    if ADelayedUpdate then UpdateStackOnTimer := true;
   end;
   end;
 end;
 end;
 
 
+procedure TLazPaintInstance.InvalidateLayerStack;
+begin
+  if FLayerStack<> nil then
+    FLayerStack.InvalidateStack(false);
+end;
+
+procedure TLazPaintInstance.UpdateLayerStackOnTimer;
+begin
+  UpdateStackOnTimer := true;
+end;
+
 function TLazPaintInstance.MakeNewBitmapReplacement(AWidth, AHeight: integer; AColor: TBGRAPixel): TBGRABitmap;
 function TLazPaintInstance.MakeNewBitmapReplacement(AWidth, AHeight: integer; AColor: TBGRAPixel): TBGRABitmap;
 begin
 begin
   result := TBGRABitmap.Create(AWidth,AHeight, AColor);
   result := TBGRABitmap.Create(AWidth,AHeight, AColor);

+ 0 - 23
lazpaint/lazpaintmainform.lfm

@@ -7,7 +7,6 @@ object FMain: TFMain
   Caption = 'LazPaint'
   Caption = 'LazPaint'
   ClientHeight = 572
   ClientHeight = 572
   ClientWidth = 739
   ClientWidth = 739
-  Color = clSkyBlue
   Constraints.MinWidth = 320
   Constraints.MinWidth = 320
   Font.Height = -12
   Font.Height = -12
   KeyPreview = True
   KeyPreview = True
@@ -20,12 +19,6 @@ object FMain: TFMain
   OnHide = FormHide
   OnHide = FormHide
   OnKeyDown = FormKeyDown
   OnKeyDown = FormKeyDown
   OnKeyUp = FormKeyUp
   OnKeyUp = FormKeyUp
-  OnMouseDown = FormMouseDown
-  OnMouseEnter = FormMouseEnter
-  OnMouseMove = FormMouseMove
-  OnMouseUp = FormMouseUp
-  OnMouseWheel = FormMouseWheel
-  OnPaint = FormPaint
   OnResize = FormResize
   OnResize = FormResize
   OnShow = FormShow
   OnShow = FormShow
   OnUTF8KeyPress = FormUTF8KeyPress
   OnUTF8KeyPress = FormUTF8KeyPress
@@ -2342,22 +2335,6 @@ object FMain: TFMain
       end
       end
     end
     end
   end
   end
-  object PaintBox_Picture: TPaintBox
-    Left = 608
-    Height = 84
-    Top = 56
-    Width = 117
-    Anchors = [akTop, akLeft, akRight, akBottom]
-    Font.Height = -12
-    ParentFont = False
-    Visible = False
-    OnMouseDown = PaintBox_PictureMouseDown
-    OnMouseEnter = PaintBox_PictureMouseEnter
-    OnMouseMove = PaintBox_PictureMouseMove
-    OnMouseUp = PaintBox_PictureMouseUp
-    OnMouseWheel = PaintBox_PictureMouseWheel
-    OnPaint = PaintBox_PicturePaint
-  end
   object Panel_Brush: TPanel
   object Panel_Brush: TPanel
     Left = 8
     Left = 8
     Height = 36
     Height = 36

+ 93 - 461
lazpaint/lazpaintmainform.pas

@@ -5,10 +5,6 @@ unit LazpaintMainForm;
 
 
 interface
 interface
 
 
-{$IFDEF DARWIN}
-  {$DEFINE USEPAINTBOXPICTURE}
-{$ENDIF}
-
 uses
 uses
   Classes, LMessages, SysUtils, LazFileUtils, LResources, Forms, Controls,
   Classes, LMessages, SysUtils, LazFileUtils, LResources, Forms, Controls,
   Graphics, Dialogs, Menus, ExtDlgs, ComCtrls, ActnList, StdCtrls, ExtCtrls,
   Graphics, Dialogs, Menus, ExtDlgs, ComCtrls, ActnList, StdCtrls, ExtCtrls,
@@ -21,7 +17,7 @@ uses
   ubrowseimages, UToolPolygon, UToolVectorial, LCVectorRectShapes,
   ubrowseimages, UToolPolygon, UToolVectorial, LCVectorRectShapes,
   LCVectorialFillControl, LCVectorialFill,
   LCVectorialFillControl, LCVectorialFill,
 
 
-  laztablet, udarktheme, UScriptType;
+  udarktheme, UScriptType;
 
 
 type
 type
   { TFMain }
   { TFMain }
@@ -345,7 +341,6 @@ type
     Panel_Text: TPanel;
     Panel_Text: TPanel;
     ToolBar15: TToolBar;
     ToolBar15: TToolBar;
     Tool_TextFont: TToolButton;
     Tool_TextFont: TToolButton;
-    PaintBox_Picture: TPaintBox;
     PaintBox_PenPreview: TPaintBox;
     PaintBox_PenPreview: TPaintBox;
     Panel_Embedded: TPanel;
     Panel_Embedded: TPanel;
     Panel_PenWidthPreview: TPanel;
     Panel_PenWidthPreview: TPanel;
@@ -480,7 +475,6 @@ type
     procedure FileUseImageBrowserUpdate(Sender: TObject);
     procedure FileUseImageBrowserUpdate(Sender: TObject);
     procedure ForgetDialogAnswersExecute(Sender: TObject);
     procedure ForgetDialogAnswersExecute(Sender: TObject);
     procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
     procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
-    procedure FormMouseLeave(Sender: TObject);
     procedure FormWindowStateChange(Sender: TObject);
     procedure FormWindowStateChange(Sender: TObject);
     procedure ItemDockLayersAndColorsClick(Sender: TObject);
     procedure ItemDockLayersAndColorsClick(Sender: TObject);
     procedure ItemFullscreenClick(Sender: TObject);
     procedure ItemFullscreenClick(Sender: TObject);
@@ -518,7 +512,6 @@ type
     procedure FileSaveSelectionAsUpdate(Sender: TObject);
     procedure FileSaveSelectionAsUpdate(Sender: TObject);
     procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
     procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
     procedure FormKeyUp(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
     procedure FormKeyUp(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
-    procedure FormMouseEnter(Sender: TObject);
     procedure FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
     procedure FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
     procedure ImageCropLayerUpdate(Sender: TObject);
     procedure ImageCropLayerUpdate(Sender: TObject);
     procedure ImageFlattenExecute(Sender: TObject);
     procedure ImageFlattenExecute(Sender: TObject);
@@ -533,7 +526,6 @@ type
     procedure LayerRotateExecute(Sender: TObject);
     procedure LayerRotateExecute(Sender: TObject);
     procedure LayerRotateUpdate(Sender: TObject);
     procedure LayerRotateUpdate(Sender: TObject);
     procedure ItemDonateClick(Sender: TObject);
     procedure ItemDonateClick(Sender: TObject);
-    procedure PaintBox_PictureMouseEnter(Sender: TObject);
     procedure Perspective_TwoPlanesClick(Sender: TObject);
     procedure Perspective_TwoPlanesClick(Sender: TObject);
     procedure SpinEdit_ShapeAltitudeChange(Sender: TObject; AByUser: boolean);
     procedure SpinEdit_ShapeAltitudeChange(Sender: TObject; AByUser: boolean);
     procedure SpinEdit_BrushSpacingChange(Sender: TObject; AByUser: boolean);
     procedure SpinEdit_BrushSpacingChange(Sender: TObject; AByUser: boolean);
@@ -545,15 +537,6 @@ type
     procedure ToolButton_DonateClick(Sender: TObject);
     procedure ToolButton_DonateClick(Sender: TObject);
     procedure VectorialFill_TextureClick(Sender: TObject);
     procedure VectorialFill_TextureClick(Sender: TObject);
     procedure PaintBox_PenPreviewPaint(Sender: TObject);
     procedure PaintBox_PenPreviewPaint(Sender: TObject);
-    procedure PaintBox_PictureMouseDown(Sender: TObject; Button: TMouseButton;
-      Shift: TShiftState; X, Y: Integer);
-    procedure PaintBox_PictureMouseMove(Sender: TObject; Shift: TShiftState; X,
-      Y: Integer);
-    procedure PaintBox_PictureMouseUp(Sender: TObject; Button: TMouseButton;
-      Shift: TShiftState; X, Y: Integer);
-    procedure PaintBox_PictureMouseWheel(Sender: TObject; Shift: TShiftState;
-      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
-    procedure PaintBox_PicturePaint(Sender: TObject);
     procedure Panel_PenWidthMouseMove(Sender: TObject; {%H-}Shift: TShiftState; {%H-}X,
     procedure Panel_PenWidthMouseMove(Sender: TObject; {%H-}Shift: TShiftState; {%H-}X,
       {%H-}Y: Integer);
       {%H-}Y: Integer);
     procedure Panel_ToolbarBackgroundMouseMove(Sender: TObject;
     procedure Panel_ToolbarBackgroundMouseMove(Sender: TObject;
@@ -566,8 +549,6 @@ type
     procedure ToolAnyExecute(Sender: TObject);
     procedure ToolAnyExecute(Sender: TObject);
     procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
     procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
     procedure FormHide(Sender: TObject);
     procedure FormHide(Sender: TObject);
-    procedure FormMouseWheel(Sender: TObject; {%H-}Shift: TShiftState;
-      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
     procedure HelpAboutExecute(Sender: TObject);
     procedure HelpAboutExecute(Sender: TObject);
     procedure HelpIndexExecute(Sender: TObject);
     procedure HelpIndexExecute(Sender: TObject);
     procedure ImageChangeCanvasSizeExecute(Sender: TObject);
     procedure ImageChangeCanvasSizeExecute(Sender: TObject);
@@ -633,12 +614,6 @@ type
     procedure FormResize(Sender: TObject);
     procedure FormResize(Sender: TObject);
     procedure ImageActionExecute(Sender: TObject);
     procedure ImageActionExecute(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
-    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
-      Shift: TShiftState; X, Y: Integer);
-    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
-    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
-      Shift: TShiftState; X, Y: Integer);
-    procedure FormPaint(Sender: TObject);
     procedure FormShow(Sender: TObject);
     procedure FormShow(Sender: TObject);
     procedure Image_SwapColorsMouseDown(Sender: TObject; {%H-}Button: TMouseButton;
     procedure Image_SwapColorsMouseDown(Sender: TObject; {%H-}Button: TMouseButton;
       {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
       {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
@@ -688,6 +663,10 @@ type
     procedure ManagerToleranceChanged(Sender: TObject);
     procedure ManagerToleranceChanged(Sender: TObject);
     procedure ManagerToolbarChanged(Sender: TObject);
     procedure ManagerToolbarChanged(Sender: TObject);
     procedure Perspective_RepeatClick(Sender: TObject);
     procedure Perspective_RepeatClick(Sender: TObject);
+    procedure PictureMouseBefore(Sender: TObject; AShift: TShiftState);
+    procedure PictureMouseMove(Sender: TObject; APosition: TPointF);
+    procedure PictureOnPaint(Sender: TObject);
+    procedure PictureToolbarUpdate(Sender: TObject);
     function ScriptShowColorDialog(AVars: TVariableSet): TScriptResult;
     function ScriptShowColorDialog(AVars: TVariableSet): TScriptResult;
     procedure VectorialFill_Change(Sender: TObject);
     procedure VectorialFill_Change(Sender: TObject);
     procedure VectorialFill_TypeChange(Sender: TObject);
     procedure VectorialFill_TypeChange(Sender: TObject);
@@ -711,9 +690,6 @@ type
     FBrowseBrushes: TFBrowseImages;
     FBrowseBrushes: TFBrowseImages;
     FSaveImage: TFBrowseImages;
     FSaveImage: TFBrowseImages;
     FSaveSelection: TFBrowseImages;
     FSaveSelection: TFBrowseImages;
-
-    FTablet: TLazTablet;
-
     FLoadInitialDir, FSaveInitialDir, FExportInitialDir: string;
     FLoadInitialDir, FSaveInitialDir, FExportInitialDir: string;
     FSaveSelectionInitialFilename: string;
     FSaveSelectionInitialFilename: string;
     FInFillChange, FInPenWidthChange, FInBrush, FInShapeRatio, FInEraserOption,
     FInFillChange, FInPenWidthChange, FInBrush, FInShapeRatio, FInEraserOption,
@@ -723,31 +699,20 @@ type
     FOnlineUpdater: TLazPaintCustomOnlineUpdater;
     FOnlineUpdater: TLazPaintCustomOnlineUpdater;
     FInitialized: boolean;
     FInitialized: boolean;
     FShouldArrange: boolean;
     FShouldArrange: boolean;
-    btnLeftDown, btnRightDown, btnMiddleDown: boolean;
     spacePressed, altPressed, snapPressed, shiftPressed: boolean;
     spacePressed, altPressed, snapPressed, shiftPressed: boolean;
-    FormMouseMovePos: TPoint;
-    InFormMouseMove: boolean;
-    InFormPaint: boolean;
     FirstPaint, LoadToolWindow: boolean;
     FirstPaint, LoadToolWindow: boolean;
-    CanCompressOrUpdateStack: boolean;
     FShowSelectionNormal: boolean;
     FShowSelectionNormal: boolean;
     FLazPaintInstance: TLazPaintCustomInstance;
     FLazPaintInstance: TLazPaintCustomInstance;
     Config: TLazPaintConfig;
     Config: TLazPaintConfig;
     StartDirectory: string;
     StartDirectory: string;
     previousToolImg: integer;
     previousToolImg: integer;
     currentToolLabel: string;
     currentToolLabel: string;
-    InShowNoPicture: boolean;
     FTopMostInfo: TTopMostInfo;
     FTopMostInfo: TTopMostInfo;
-    DelayedPaintPicture, CatchPaintPicture, PaintPictureCatched: boolean;
     Panel_LineCap_FullSize: integer;
     Panel_LineCap_FullSize: integer;
     FCoordinatesCaption: string;
     FCoordinatesCaption: string;
     FCoordinatesCaptionCount: NativeInt;
     FCoordinatesCaptionCount: NativeInt;
-    FImageView: TImageView;
-    FLastPaintDate: TDateTime;
-    FUpdateStackWhenIdle: boolean;
     FToolbarElementsInitDone: boolean;
     FToolbarElementsInitDone: boolean;
 
 
-    function GetCurrentPressure: single;
     function GetDarkTheme: boolean;
     function GetDarkTheme: boolean;
     function GetImageAction: TImageActions;
     function GetImageAction: TImageActions;
     function GetUpdatingPopup: boolean;
     function GetUpdatingPopup: boolean;
@@ -789,7 +754,6 @@ type
 
 
     procedure CreateMenuAndToolbar;
     procedure CreateMenuAndToolbar;
     function GetToolManager: TToolManager;
     function GetToolManager: TToolManager;
-    procedure LayoutPictureAreaChange({%H-}ASender: TObject; {%H-}ANewArea: TRect);
     function GetCurrentTool: TPaintToolType;
     function GetCurrentTool: TPaintToolType;
     procedure SwitchColors;
     procedure SwitchColors;
     function EditingColors: boolean;
     function EditingColors: boolean;
@@ -797,7 +761,6 @@ type
     procedure OnLatestVersionUpdate(ANewVersion: string);
     procedure OnLatestVersionUpdate(ANewVersion: string);
     procedure ManagerToolChanged({%H-}sender: TToolManager; {%H-}ANewTool: TPaintToolType);
     procedure ManagerToolChanged({%H-}sender: TToolManager; {%H-}ANewTool: TPaintToolType);
     procedure OnQueryExitToolHandler({%H-}sender: TLazPaintImage);
     procedure OnQueryExitToolHandler({%H-}sender: TLazPaintImage);
-    procedure OnZoomChanged({%H-}sender: TZoom; {%H-}ANewZoom: single);
     procedure SetLazPaintInstance(const AValue: TLazPaintCustomInstance);
     procedure SetLazPaintInstance(const AValue: TLazPaintCustomInstance);
     procedure SetShowSelectionNormal(const AValue: boolean);
     procedure SetShowSelectionNormal(const AValue: boolean);
     procedure ToggleToolwindowsVisible;
     procedure ToggleToolwindowsVisible;
@@ -813,20 +776,15 @@ type
     procedure HidePenPreview(ATimeMs: Integer = 300; AClearTime: boolean = false);
     procedure HidePenPreview(ATimeMs: Integer = 300; AClearTime: boolean = false);
     procedure ShowFill(AFillControl: TLCVectorialFillControl; APanel: TPanel);
     procedure ShowFill(AFillControl: TLCVectorialFillControl; APanel: TPanel);
     procedure HideFill(ATimeMs: Integer = 300; AClearTime: boolean = false);
     procedure HideFill(ATimeMs: Integer = 300; AClearTime: boolean = false);
-    procedure OnPaintHandler;
     procedure OnImageChangedHandler({%H-}AEvent: TLazPaintImageObservationEvent);
     procedure OnImageChangedHandler({%H-}AEvent: TLazPaintImageObservationEvent);
     procedure OnImageRenderChanged({%H-}Sender: TObject);
     procedure OnImageRenderChanged({%H-}Sender: TObject);
     procedure LabelAutosize(ALabel: TLabel);
     procedure LabelAutosize(ALabel: TLabel);
     procedure AskMergeSelection(ACaption: string);
     procedure AskMergeSelection(ACaption: string);
-    procedure ReleaseMouseButtons(Shift: TShiftState);
     procedure UpdateSpecialKeys({%H-}Shift: TShiftState);
     procedure UpdateSpecialKeys({%H-}Shift: TShiftState);
     procedure UpdateCurveModeToolbar;
     procedure UpdateCurveModeToolbar;
     function ShowOpenTextureDialog(ATargetFill: TVectorialFill): boolean;
     function ShowOpenTextureDialog(ATargetFill: TVectorialFill): boolean;
     procedure ShowNoPicture;
     procedure ShowNoPicture;
     procedure SetCurveMode(AMode: TToolSplineMode);
     procedure SetCurveMode(AMode: TToolSplineMode);
-    procedure IncreasePenSize;
-    procedure DecreasePenSize;
-    function PenSizeDelta(direction: integer): integer;
     procedure UpdatePenWidthFromSpinEdit;
     procedure UpdatePenWidthFromSpinEdit;
     procedure UpdateWindowCaption;
     procedure UpdateWindowCaption;
     procedure ImageCurrentFilenameChanged({%H-}sender: TLazPaintImage);
     procedure ImageCurrentFilenameChanged({%H-}sender: TLazPaintImage);
@@ -864,15 +822,15 @@ type
 
 
   public
   public
     { public declarations }
     { public declarations }
-    UpdateStackOnTimer: boolean;
     Zoom: TZoom;
     Zoom: TZoom;
 
 
     procedure PaintPictureNow;
     procedure PaintPictureNow;
+    procedure PaintPictureLater;
+    procedure NotifyImagePaint;
     procedure InvalidatePicture(AInvalidateAll: boolean = true);
     procedure InvalidatePicture(AInvalidateAll: boolean = true);
     function TryOpenFileUTF8(filenameUTF8: string; AddToRecent: Boolean=True;
     function TryOpenFileUTF8(filenameUTF8: string; AddToRecent: Boolean=True;
       ALoadedImage: PImageEntry = nil; ASkipDialogIfSingleImage: boolean = false;
       ALoadedImage: PImageEntry = nil; ASkipDialogIfSingleImage: boolean = false;
       AAllowDuplicate: boolean = false; AEntryToLoad: integer = -1): Boolean;
       AAllowDuplicate: boolean = false; AEntryToLoad: integer = -1): Boolean;
-    function PictureCanvasOfs: TPoint;
     procedure UpdateLineCapBar;
     procedure UpdateLineCapBar;
     procedure UpdateFillToolbar(AUpdateColorDiff: boolean);
     procedure UpdateFillToolbar(AUpdateColorDiff: boolean);
     procedure UpdateToolbar;
     procedure UpdateToolbar;
@@ -890,7 +848,6 @@ type
     property ToolManager: TToolManager read GetToolManager;
     property ToolManager: TToolManager read GetToolManager;
     property Layout: TMainFormLayout read FLayout;
     property Layout: TMainFormLayout read FLayout;
     property UseImageBrowser: boolean read GetUseImageBrowser;
     property UseImageBrowser: boolean read GetUseImageBrowser;
-    property CurrentPressure: single read GetCurrentPressure;
     property DarkTheme: boolean read GetDarkTheme write SetDarkTheme;
     property DarkTheme: boolean read GetDarkTheme write SetDarkTheme;
     property Initialized: boolean read FInitialized;
     property Initialized: boolean read FInitialized;
     property UpdatingPopup: boolean read GetUpdatingPopup write SetUpdatingPopup;
     property UpdatingPopup: boolean read GetUpdatingPopup write SetUpdatingPopup;
@@ -915,17 +872,16 @@ procedure TFMain.FormCreate(Sender: TObject);
 begin
 begin
   FInitialized := false;
   FInitialized := false;
 
 
-  FLayout := TMainFormLayout.Create(self);
-  FImageView := nil;
+  Zoom := TZoom.Create(Label_CurrentZoom,Edit_Zoom,FLayout);
+  FLayout := TMainFormLayout.Create(self, Zoom);
+  FLayout.OnPaintPicture:=@PictureOnPaint;
+  FLayout.OnToolbarUpdate:=@PictureToolbarUpdate;
+  FLayout.OnPictureMouseMove:=@PictureMouseMove;
+  FLayout.OnPictureMouseBefore:=@PictureMouseBefore;
 
 
   ScaleControl(Self,OriginalDPI);
   ScaleControl(Self,OriginalDPI);
   self.Color := clBtnFace; //toolbar color inherited on mac
   self.Color := clBtnFace; //toolbar color inherited on mac
 
 
-  {$IFDEF USEPAINTBOXPICTURE}
-  PaintBox_Picture.SetBounds(0,0,ClientWidth,ClientHeight);
-  PaintBox_Picture.Visible := True;
-  {$ENDIF}
-
   //mac interface
   //mac interface
   CheckActions(ActionList1);
   CheckActions(ActionList1);
   CheckQuitMenu(ItemQuit,ItemQuitSeparator);
   CheckQuitMenu(ItemQuit,ItemQuitSeparator);
@@ -944,29 +900,13 @@ begin
   ExportPictureDialog.Filter := SavePictureDialog1.Filter;
   ExportPictureDialog.Filter := SavePictureDialog1.Filter;
   SaveSelectionDialog.Filter := SavePictureDialog1.Filter;
   SaveSelectionDialog.Filter := SavePictureDialog1.Filter;
 
 
-  Zoom := TZoom.Create(Label_CurrentZoom,Edit_Zoom,FLayout);
-  Zoom.OnZoomChanged:= @OnZoomChanged;
   previousToolImg:= -1;
   previousToolImg:= -1;
 
 
-  //mouse status
-  btnLeftDown := false;
-  btnRightDown := false;
-  btnMiddleDown:= false;
-  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;
   shiftPressed:= false;
   shiftPressed:= false;
 
 
-  //recursive calls
-  InFormMouseMove:= false;
-  InFormPaint := false;
-
   {$IFDEF LINUX}
   {$IFDEF LINUX}
   ComboBox_BrushSelect.Top := ComboBox_BrushSelect.Top - 2;
   ComboBox_BrushSelect.Top := ComboBox_BrushSelect.Top - 2;
   ComboBox_BrushSelect.Font.Height := -10;
   ComboBox_BrushSelect.Font.Height := -10;
@@ -978,56 +918,10 @@ begin
   ComboBox_ArrowEnd.Font.Height := ComboBox_BrushSelect.Font.Height;
   ComboBox_ArrowEnd.Font.Height := ComboBox_BrushSelect.Font.Height;
   {$ENDIF}
   {$ENDIF}
 
 
-  FLayout.OnPictureAreaChange := @LayoutPictureAreaChange;
   FInitialized := true;
   FInitialized := true;
   FirstPaint := true;
   FirstPaint := true;
 end;
 end;
 
 
-function TFMain.CatchToolKeyDown(var AKey: Word): boolean;
-begin
-  if Assigned(ToolManager) then
-  begin
-    CatchPaintPicture:= true;
-    PaintPictureCatched := false;
-    try
-      result := ToolManager.ToolKeyDown(AKey) or PaintPictureCatched;
-    finally
-      CatchPaintPicture:= false;
-    end;
-  end else
-    result := false;
-end;
-
-function TFMain.CatchToolKeyUp(var AKey: Word): boolean;
-begin
-  if Assigned(ToolManager) then
-  begin
-    CatchPaintPicture:= true;
-    PaintPictureCatched := false;
-    try
-       result := ToolManager.ToolKeyUp(AKey) or PaintPictureCatched;
-    finally
-      CatchPaintPicture:= false;
-    end;
-  end else
-    result := false;
-end;
-
-function TFMain.CatchToolKeyPress(var AKey: TUTF8Char): boolean;
-begin
-  if Assigned(ToolManager) then
-  begin
-    CatchPaintPicture:= true;
-    PaintPictureCatched := false;
-    try
-      result := ToolManager.ToolKeyPress(AKey) or PaintPictureCatched;
-    finally
-      CatchPaintPicture:= false;
-    end;
-  end else
-    result := false;
-end;
-
 procedure TFMain.CreateMenuAndToolbar;
 procedure TFMain.CreateMenuAndToolbar;
 begin
 begin
   CreateToolbarElements;
   CreateToolbarElements;
@@ -1079,8 +973,6 @@ begin
   FreeAndNil(Zoom);
   FreeAndNil(Zoom);
   FreeAndNil(FOnlineUpdater);
   FreeAndNil(FOnlineUpdater);
 
 
-  FreeAndNil(FTablet);
-
   FreeAndNil(FBrowseSelections);
   FreeAndNil(FBrowseSelections);
   FreeAndNil(FBrowseImages);
   FreeAndNil(FBrowseImages);
   FreeAndNil(FBrowseTextures);
   FreeAndNil(FBrowseTextures);
@@ -1095,7 +987,6 @@ begin
   FreeAndNil(FSaveImage);
   FreeAndNil(FSaveImage);
   FreeAndNil(FSaveSelection);
   FreeAndNil(FSaveSelection);
 
 
-  FreeAndNil(FImageView);
   FreeAndNil(FLayout);
   FreeAndNil(FLayout);
 end;
 end;
 
 
@@ -1137,9 +1028,6 @@ begin
     ExportPictureDialog.FilterIndex:= 1;
     ExportPictureDialog.FilterIndex:= 1;
   end;
   end;
 
 
-  FImageView := TImageView.Create(LazPaintInstance, Zoom,
-                {$IFDEF USEPAINTBOXPICTURE}PaintBox_Picture.Canvas{$ELSE}self.Canvas{$ENDIF});
-
   LazPaintInstance.EmbeddedResult := mrNone;
   LazPaintInstance.EmbeddedResult := mrNone;
 
 
   Image.OnSelectedLayerIndexChanged:= @PictureSelectedLayerIndexChanged;
   Image.OnSelectedLayerIndexChanged:= @PictureSelectedLayerIndexChanged;
@@ -1316,146 +1204,6 @@ begin
   Scripting.RegisterScriptFunction('ShowColorDialog',@ScriptShowColorDialog,ARegister);
   Scripting.RegisterScriptFunction('ShowColorDialog',@ScriptShowColorDialog,ARegister);
 end;
 end;
 
 
-procedure TFMain.FormMouseDown(Sender: TObject; Button: TMouseButton;
-  Shift: TShiftState; X, Y: Integer);
-begin
-  if not Assigned(FImageView) then exit;
-  ReleaseMouseButtons(Shift);
-  if not (Button in[mbLeft,mbRight,mbMiddle]) or not FImageView.PictureCoordsDefined then exit;
-  CanCompressOrUpdateStack := false;
-  if Assigned(LazPaintInstance) then LazPaintInstance.ExitColorEditor;
-  Image.OnImageChanged.DelayedStackUpdate := True;
-
-  if btnLeftDown or btnRightDown or btnMiddleDown then exit;
-
-  if Button = mbMiddle then
-  begin
-    btnMiddleDown:= true;
-    if not ToolManager.ToolSleeping and not (ssAlt in Shift) then ToolManager.ToolSleep;
-  end;
-
-  if FImageView.PictureCoordsDefined then
-  begin
-    if Button = mbLeft then
-      btnLeftDown := true else
-    if Button = mbRight then
-      btnRightDown := true;
-
-    if (
-        (ToolManager.GetCurrentToolType = ptHand) or
-        ((ToolManager.GetCurrentToolType = ptEditShape) and
-          Assigned(ToolManager.CurrentTool) and
-          (ToolManager.CurrentTool as TEditShapeTool).NothingSelected)
-       )  and
-       (ssShift in Shift) then
-      Image.SelectLayerContainingPixelAt(FImageView.FormToBitmap(X,Y).Round);
-
-    if ToolManager.ToolDown(FImageView.FormToBitmap(X,Y),
-        btnRightDown{$IFDEF DARWIN} or (ssCtrl in Shift){$ENDIF},
-        CurrentPressure) then
-        PaintPictureNow;
-    UpdateToolbar;
-  end;
-end;
-
-procedure TFMain.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
-  Y: Integer);
-var BmpPos: TPointF;
-    updateForVSCursor: boolean;
-
-//var tickstart:DWord;
-begin
-  //tickstart := GetTickCount;
-  if not Assigned(FImageView) then exit;
-
-  ReleaseMouseButtons(Shift);
-  UpdateSpecialKeys(Shift);
-  HidePenPreview;
-  HideFill;
-  if LazPaintInstance.TopMostHasFocus then
-  begin
-    if LazPaintInstance.TopMostOkToUnfocus then
-      SafeSetFocus(self)
-    else
-      exit;
-  end;
-  if (CurrentTool in[ptText,ptEditShape]) and TextSpinEditFocused then VectorialFill_Pen.SetFocus;
-  Image.CurrentState.LayeredBitmap.EditorFocused := true;
-
-  FormMouseMovePos := Point(X,Y);
-  if InFormMouseMove then exit;
-  InFormMouseMove := True;
-  if not FImageView.PictureCoordsDefined then
-    Application.ProcessMessages; //empty message stack
-  if not FImageView.PictureCoordsDefined then
-  begin
-    InFormMouseMove:= false;
-    exit;
-  end;
-
-  BmpPos := FImageView.FormToBitmap(FormMouseMovePos);
-  FCoordinatesCaption := IntToStr(round(BmpPos.X))+','+IntToStr(round(BmpPos.Y));
-  Inc(FCoordinatesCaptionCount);
-  if FCoordinatesCaptionCount > 8 then
-  begin
-    FCoordinatesCaptionCount := 0;
-    Label_Coordinates.caption := FCoordinatesCaption;
-    Label_Coordinates.Update;
-    UpdateStatusText;
-  end;
-  updateForVSCursor:= false;
-  if ToolManager.ToolMove(BmpPos,CurrentPressure) then
-  begin
-    FImageView.UpdatePicture(PictureCanvasOfs, FLayout.WorkArea, self);
-  end else
-    updateForVSCursor := true;
-  UpdateToolbar;
-
-  if updateForVSCursor then
-    FImageView.UpdateCursor(X,Y, PictureCanvasOfs, FLayout.WorkArea,
-                            {$IFDEF USEPAINTBOXPICTURE}PaintBox_Picture{$ELSE}self{$ENDIF},
-                            Point(0,0), self);
-
-  if ToolManager.ToolSleeping and not spacePressed and not btnLeftDown and not btnRightDown
-    and not btnMiddleDown then
-    ToolManager.ToolWakeUp;
-
-  InFormMouseMove := False;
-  //Canvas.TextOut(FLayout.WorkArea.Left,FLayout.WorkArea.Top,inttostr(GetTickCount-tickstart)+'     ');
-end;
-
-procedure TFMain.FormMouseUp(Sender: TObject; Button: TMouseButton;
-  Shift: TShiftState; X, Y: Integer);
-var redraw: boolean;
-begin
-  if not Assigned(FImageView) then exit;
-
-  redraw := false;
-  if (btnLeftDown and (Button = mbLeft)) or (btnRightDown and (Button=mbRight))
-    or (btnMiddleDown and (Button = mbMiddle)) then
-  begin
-    if FImageView.PictureCoordsDefined then
-      redraw := ToolManager.ToolMove(FImageView.FormToBitmap(X,Y),CurrentPressure)
-      else redraw := false;
-    if ToolManager.ToolUp then redraw := true;
-    btnLeftDown := false;
-    btnRightDown := false;
-    btnMiddleDown:= false;
-  end;
-  if redraw then PaintPictureNow;
-  if FUpdateStackWhenIdle then
-  begin
-    UpdateStackOnTimer:= true;
-    FUpdateStackWhenIdle:= false;
-  end;
-  UpdateToolbar;
-  ReleaseMouseButtons(Shift);
-
-  if ToolManager.ToolSleeping and not spacePressed and not btnLeftDown and not btnRightDown
-   and not btnMiddleDown then
-    ToolManager.ToolWakeUp;
-end;
-
 function TFMain.ScriptFileOpen(AVars: TVariableSet): TScriptResult;
 function TFMain.ScriptFileOpen(AVars: TVariableSet): TScriptResult;
 var vFilename: TScriptVariableReference;
 var vFilename: TScriptVariableReference;
     topInfo: TTopMostInfo;
     topInfo: TTopMostInfo;
@@ -2030,7 +1778,7 @@ begin
     if Zoom.EditingZoom or EditingColors then exit;
     if Zoom.EditingZoom or EditingColors then exit;
     if not ((CurrentTool = ptText) and TextSpinEditFocused and (Key = VK_BACK)) and CatchToolKeyDown(Key) then
     if not ((CurrentTool = ptText) and TextSpinEditFocused and (Key = VK_BACK)) and CatchToolKeyDown(Key) then
     begin
     begin
-      DelayedPaintPicture := True;
+      PaintPictureLater;
     end else
     end else
     if Key = VK_F6 then
     if Key = VK_F6 then
     begin
     begin
@@ -2041,7 +1789,7 @@ begin
     begin
     begin
       spacePressed:= true;
       spacePressed:= true;
       Key := 0;
       Key := 0;
-      if not ToolManager.ToolSleeping and not btnLeftDown and not btnRightDown then ToolManager.ToolSleep;
+      if not ToolManager.ToolSleeping and ([ssLeft,ssRight] * FLayout.MouseButtonState = []) then ToolManager.ToolSleep;
     end else
     end else
     if LazPaintInstance.ImageListWindowVisible then
     if LazPaintInstance.ImageListWindowVisible then
       LazPaintInstance.ImageListWindowVisibleKeyDown(Key,Shift);
       LazPaintInstance.ImageListWindowVisibleKeyDown(Key,Shift);
@@ -2450,22 +2198,18 @@ begin
   else if Key = VK_SHIFT then shiftPressed:= false;
   else if Key = VK_SHIFT then shiftPressed:= false;
   if CatchToolKeyUp(Key) then
   if CatchToolKeyUp(Key) then
   begin
   begin
-    DelayedPaintPicture := True;
+    PaintPictureLater;
   end else
   end else
   If Key = VK_SPACE then
   If Key = VK_SPACE then
   begin
   begin
     spacePressed:= false;
     spacePressed:= false;
-    if ToolManager.ToolSleeping and not spacePressed and not btnRightDown and not btnLeftDown then
+    if ToolManager.ToolSleeping and not spacePressed and
+       ([ssLeft,ssRight] * FLayout.MouseButtonState = []) then
       ToolManager.ToolWakeUp;
       ToolManager.ToolWakeUp;
     Key := 0;
     Key := 0;
   end;
   end;
 end;
 end;
 
 
-procedure TFMain.FormMouseEnter(Sender: TObject);
-begin
-  Image.PrepareForRendering;
-end;
-
 procedure TFMain.FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
 procedure TFMain.FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
 var selectedTool: TPaintToolType;
 var selectedTool: TPaintToolType;
   toolProcessKey: boolean;
   toolProcessKey: boolean;
@@ -2480,7 +2224,7 @@ begin
     end;
     end;
     if toolProcessKey and CatchToolKeyPress(UTF8Key) then
     if toolProcessKey and CatchToolKeyPress(UTF8Key) then
     begin
     begin
-      DelayedPaintPicture := true;
+      PaintPictureLater;
       UpdateToolbar;
       UpdateToolbar;
     end else
     end else
     if UTF8Key <> '' then
     if UTF8Key <> '' then
@@ -2522,11 +2266,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TFMain.FormMouseLeave(Sender: TObject);
-begin
-  Cursor := crDefault;
-end;
-
 procedure TFMain.FormWindowStateChange(Sender: TObject);
 procedure TFMain.FormWindowStateChange(Sender: TObject);
 begin
 begin
   {$IFDEF LINUX}
   {$IFDEF LINUX}
@@ -2694,43 +2433,6 @@ begin
   LazPaintInstance.Donate;
   LazPaintInstance.Donate;
 end;
 end;
 
 
-procedure TFMain.PaintBox_PictureMouseEnter(Sender: TObject);
-begin
-  FormMouseEnter(Sender);
-end;
-
-procedure TFMain.PaintBox_PictureMouseDown(Sender: TObject;
-  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
-begin
-  FormMouseDown(Sender,Button,Shift,X+PaintBox_Picture.Left,Y+PaintBox_Picture.Top);
-end;
-
-procedure TFMain.PaintBox_PictureMouseMove(Sender: TObject; Shift: TShiftState;
-  X, Y: Integer);
-begin
-  FormMouseMove(Sender,Shift,X+PaintBox_Picture.Left,Y+PaintBox_Picture.Top);
-end;
-
-procedure TFMain.PaintBox_PictureMouseUp(Sender: TObject; Button: TMouseButton;
-  Shift: TShiftState; X, Y: Integer);
-begin
-  FormMouseUp(Sender,Button,Shift,X+PaintBox_Picture.Left,Y+PaintBox_Picture.Top);
-end;
-
-procedure TFMain.PaintBox_PictureMouseWheel(Sender: TObject;
-  Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
-  var Handled: Boolean);
-begin
-  FormMouseWheel(Sender,Shift,WheelDelta,Point(MousePos.X+PaintBox_Picture.Left,MousePos.Y+PaintBox_Picture.Top),Handled);
-end;
-
-procedure TFMain.PaintBox_PicturePaint(Sender: TObject);
-begin
-  {$IFDEF USEPAINTBOXPICTURE}
-    OnPaintHandler;
-  {$ENDIF}
-end;
-
 procedure TFMain.FormCloseQuery(Sender: TObject; var CanClose: boolean);
 procedure TFMain.FormCloseQuery(Sender: TObject; var CanClose: boolean);
 var topmostInfo: TTopMostInfo;
 var topmostInfo: TTopMostInfo;
 begin
 begin
@@ -2784,24 +2486,6 @@ begin
   LazPaintInstance.SaveMainWindowPosition;
   LazPaintInstance.SaveMainWindowPosition;
 end;
 end;
 
 
-procedure TFMain.FormMouseWheel(Sender: TObject; Shift: TShiftState;
-  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
-begin
-  if not Assigned(FImageView) or not FImageView.PictureCoordsDefined then exit;
-  if ssAlt in Shift then
-  begin
-    if WheelDelta > 0 then IncreasePenSize
-    else if WheelDelta < 0 then DecreasePenSize;
-  end else
-  begin
-    Zoom.SetPosition(FImageView.FormToBitmap(MousePos.X,MousePos.Y), MousePos);
-    if WheelDelta > 0 then Zoom.ZoomIn(ssSnap in Shift) else
-    if WheelDelta < 0 then Zoom.ZoomOut(ssSnap in Shift);
-    Zoom.ClearPosition;
-  end;
-  Handled := True;
-end;
-
 procedure TFMain.HelpAboutExecute(Sender: TObject);
 procedure TFMain.HelpAboutExecute(Sender: TObject);
 begin
 begin
   LazPaintInstance.ShowAboutDlg;
   LazPaintInstance.ShowAboutDlg;
@@ -2896,9 +2580,11 @@ begin
 end;
 end;
 
 
 procedure TFMain.TimerUpdateTimer(Sender: TObject);
 procedure TFMain.TimerUpdateTimer(Sender: TObject);
-const SelectionPaintDelay = 100/(1000*60*60*24);
 begin
 begin
   TimerUpdate.Enabled := false;
   TimerUpdate.Enabled := false;
+  if ToolManager.ToolSleeping and not spacePressed and
+     ([ssLeft,ssRight,ssMiddle] * FLayout.MouseButtonState = []) then
+    ToolManager.ToolWakeUp;
   EditUndo.Update;
   EditUndo.Update;
   EditRedo.Update;
   EditRedo.Update;
   UpdateStatusText;
   UpdateStatusText;
@@ -2908,22 +2594,7 @@ begin
     Label_Coordinates.Update;
     Label_Coordinates.Update;
     FCoordinatesCaptionCount := 0;
     FCoordinatesCaptionCount := 0;
   end;
   end;
-  if CanCompressOrUpdateStack and UpdateStackOnTimer then
-  begin
-    LazPaintInstance.NotifyStackChange;
-    UpdateStackOnTimer := false;
-  end else
-  begin
-    if CanCompressOrUpdateStack then image.CompressUndo;
-  end;
-  if DelayedPaintPicture or ToolManager.ToolUpdateNeeded or
-   (Assigned(FImageView) and not FImageView.ShowSelection and
-    (Now > FLastPaintDate+SelectionPaintDelay) ) then
-  begin
-    if ToolManager.ToolUpdateNeeded then ToolManager.ToolUpdate;
-    if Assigned(FImageView) then FImageView.ShowSelection := true;
-    PaintPictureNow;
-  end;
+  FLayout.CheckDelayedUpdate;
   TimerUpdate.Enabled := true;
   TimerUpdate.Enabled := true;
 end;
 end;
 
 
@@ -3076,14 +2747,6 @@ begin
   params.Free;
   params.Free;
 end;
 end;
 
 
-procedure TFMain.LayoutPictureAreaChange(ASender: TObject; ANewArea: TRect);
-begin
-   {$IFDEF USEPAINTBOXPICTURE}
-   PaintBox_Picture.SetBounds(ANewArea.Left,ANewArea.Top,ANewArea.Right-ANewArea.Left,ANewArea.Bottom-ANewArea.Top);
-   {$ENDIF}
-   if Assigned(FImageView) then FImageView.InvalidatePicture(True, ANewArea, Point(0,0), self);
-end;
-
 procedure TFMain.ToggleGridVisible;
 procedure TFMain.ToggleGridVisible;
 begin
 begin
   LazPaintInstance.GridVisible := not LazPaintInstance.GridVisible;
   LazPaintInstance.GridVisible := not LazPaintInstance.GridVisible;
@@ -3301,8 +2964,7 @@ begin
         ToolManager.ToolMove(texMapBounds.Right-0.5, texMapBounds.Bottom-0.5, 1);
         ToolManager.ToolMove(texMapBounds.Right-0.5, texMapBounds.Bottom-0.5, 1);
         ToolManager.ToolUp;
         ToolManager.ToolUp;
       end;
       end;
-      if Assigned(FImageView) then
-        FImageView.FillSelectionHighlight := ToolManager.DisplayFilledSelection and not FShowSelectionNormal;
+      FLayout.FillSelectionHighlight := ToolManager.DisplayFilledSelection and not FShowSelectionNormal;
     except
     except
       on ex:Exception do
       on ex:Exception do
       begin
       begin
@@ -3382,7 +3044,6 @@ begin
 
 
   if needUpdate then
   if needUpdate then
   begin
   begin
-    FImageView.UpdatePicture(PictureCanvasOfs, FLayout.WorkArea, self);
     PaintPictureNow;
     PaintPictureNow;
     UpdateToolbar;
     UpdateToolbar;
   end;
   end;
@@ -3460,7 +3121,6 @@ begin
 
 
   if needUpdate then
   if needUpdate then
   begin
   begin
-    FImageView.UpdatePicture(PictureCanvasOfs, FLayout.WorkArea, self);
     PaintPictureNow;
     PaintPictureNow;
     UpdateToolbar;
     UpdateToolbar;
   end;
   end;
@@ -3508,7 +3168,6 @@ begin
     end;
     end;
     if needUpdate then
     if needUpdate then
     begin
     begin
-      FImageView.UpdatePicture(PictureCanvasOfs, FLayout.WorkArea, self);
       PaintPictureNow;
       PaintPictureNow;
       UpdateToolbar;
       UpdateToolbar;
     end;
     end;
@@ -4007,30 +3666,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TFMain.ReleaseMouseButtons(Shift: TShiftState);
-begin
-  if not (ssLeft in Shift) and btnLeftDown then
-  begin
-    btnLeftDown := false;
-    if ToolManager.ToolUp then PaintPictureNow;
-  end;
-  if not (ssRight in Shift) and btnRightDown then
-  begin
-    btnRightDown := false;
-    if ToolManager.ToolUp then PaintPictureNow;
-  end;
-  if not (ssMiddle in Shift) and btnMiddleDown then
-  begin
-    btnMiddleDown := false;
-    if ToolManager.ToolUp then PaintPictureNow;
-  end;
-  if not btnLeftDown and not btnRightDown then
-  begin
-    CanCompressOrUpdateStack := true;
-    Image.OnImageChanged.DelayedStackUpdate := False;
-  end;
-end;
-
 procedure TFMain.UpdateSpecialKeys(Shift: TShiftState);
 procedure TFMain.UpdateSpecialKeys(Shift: TShiftState);
   procedure UpdateKey(AShift: TShiftStateEnum; ACode: Word; var APressed: boolean);
   procedure UpdateKey(AShift: TShiftStateEnum; ACode: Word; var APressed: boolean);
   begin
   begin
@@ -4194,9 +3829,8 @@ end;
 
 
 procedure TFMain.ShowNoPicture;
 procedure TFMain.ShowNoPicture;
 begin
 begin
-  InShowNoPicture := true;
-  PaintPictureNow;
-  InShowNoPicture:= false;
+  if Assigned(FLayout) then
+    FLayout.ShowNoPicture;
 end;
 end;
 
 
 procedure TFMain.UpdateWindowCaption;
 procedure TFMain.UpdateWindowCaption;
@@ -4430,36 +4064,8 @@ end;
 
 
 {****************************** Picture ************************}
 {****************************** Picture ************************}
 
 
-procedure TFMain.OnPaintHandler;
-var
-  ac: TWinControl;
-begin
-  if FirstPaint then
-  begin
-    LoadToolwindow := True;
-    TimerLoadToolWin.Enabled := true;
-    FirstPaint := false;
-  end;
-  if InFormPaint then exit;
-  InFormPaint := true;
-
-  if Assigned(FImageView) then FImageView.DoPaint(PictureCanvasOfs, FLayout.WorkArea, InShowNoPicture);
-  DelayedPaintPicture:= false;
-
-  ac := ActiveControl;
-  if ac is TBCTrackbarUpdown then
-    TBCTrackbarUpdown(ac).DelayTimer;
-
-  InFormPaint := false;
-  FLastPaintDate := Now;
-end;
-
 procedure TFMain.OnImageChangedHandler(AEvent: TLazPaintImageObservationEvent);
 procedure TFMain.OnImageChangedHandler(AEvent: TLazPaintImageObservationEvent);
 begin
 begin
-  if CatchPaintPicture then
-    PaintPictureCatched := true
-    else InvalidatePicture(false);
-
   if (image.Width <> FLastWidth) or (image.Height <> FLastHeight)
   if (image.Width <> FLastWidth) or (image.Height <> FLastHeight)
    or (image.BPP <> FLastBPP) or (image.FrameIndex <> FLastFrameIndex) then
    or (image.BPP <> FLastBPP) or (image.FrameIndex <> FLastFrameIndex) then
   begin
   begin
@@ -4474,7 +4080,6 @@ begin
     ChooseTool(ptHand);
     ChooseTool(ptHand);
     MessagePopup(rsToolOnInvisibleLayer,5000);
     MessagePopup(rsToolOnInvisibleLayer,5000);
   end;
   end;
-  if AEvent.DelayedStackUpdate then FUpdateStackWhenIdle := true;
 end;
 end;
 
 
 procedure TFMain.OnImageRenderChanged(Sender: TObject);
 procedure TFMain.OnImageRenderChanged(Sender: TObject);
@@ -4486,37 +4091,78 @@ procedure TFMain.UpdateEditPicture(ADelayed: boolean = false);
 begin
 begin
   if ToolManager.ToolUpdate then
   if ToolManager.ToolUpdate then
   begin
   begin
-    if ADelayed then DelayedPaintPicture := True
+    if ADelayed then PaintPictureLater
     else
     else
       PaintPictureNow;
       PaintPictureNow;
   end;
   end;
 end;
 end;
 
 
-procedure TFMain.OnZoomChanged(sender: TZoom; ANewZoom: single);
+procedure TFMain.PaintPictureNow;
+begin
+  if not visible then exit;
+  if Assigned(LazPaintInstance) then LazPaintInstance.UpdateStackOnTimer := true;
+  if Assigned(FLayout) then FLayout.PaintPictureNow;
+end;
+
+procedure TFMain.PaintPictureLater;
+begin
+  if Assigned(FLayout) then FLayout.DelayedPaintPicture := True;
+end;
+
+procedure TFMain.NotifyImagePaint;
+begin
+  if Assigned(FLayout) then
+    FLayout.DelayedPaintPicture:= false;
+end;
+
+procedure TFMain.PictureMouseBefore(Sender: TObject; AShift: TShiftState);
+begin
+  UpdateSpecialKeys(AShift);
+end;
+
+procedure TFMain.PictureMouseMove(Sender: TObject; APosition: TPointF);
 begin
 begin
-  if Assigned(FImageView) then
+  HidePenPreview;
+  HideFill;
+
+  FCoordinatesCaption := IntToStr(round(APosition.X))+','+IntToStr(round(APosition.Y));
+  Inc(FCoordinatesCaptionCount);
+  if FCoordinatesCaptionCount > 8 then
   begin
   begin
-    if not Image.SelectionMaskEmpty then
-      FImageView.ShowSelection := false;
-    FImageView.OnZoomChanged(sender, ANewZoom, FLayout.WorkArea);
+    FCoordinatesCaptionCount := 0;
+    Label_Coordinates.caption := FCoordinatesCaption;
+    Label_Coordinates.Update;
+    UpdateStatusText;
   end;
   end;
-  UpdateToolbar;
-  PaintPictureNow;
+
+  if LazPaintInstance.TopMostHasFocus then
+  begin
+    if LazPaintInstance.TopMostOkToUnfocus then
+      SafeSetFocus(self)
+    else
+      exit;
+  end;
+  if (CurrentTool in[ptText,ptEditShape]) and TextSpinEditFocused then VectorialFill_Pen.SetFocus;
 end;
 end;
 
 
-procedure TFMain.PaintPictureNow;
+procedure TFMain.PictureOnPaint(Sender: TObject);
+var
+  ac: TWinControl;
 begin
 begin
-  if not visible then exit;
-  UpdateStackOnTimer := true;
-  Image.OnImageChanged.NotifyObservers;
-  {$IFDEF USEPAINTBOXPICTURE}PaintBox_Picture{$ELSE}self{$ENDIF}.Update;
+  if FirstPaint then
+  begin
+    LoadToolwindow := True;
+    TimerLoadToolWin.Enabled := true;
+    FirstPaint := false;
+  end;
+  ac := ActiveControl;
+  if ac is TBCTrackbarUpdown then
+    TBCTrackbarUpdown(ac).DelayTimer;
 end;
 end;
 
 
-procedure TFMain.FormPaint(Sender: TObject);
+procedure TFMain.PictureToolbarUpdate(Sender: TObject);
 begin
 begin
-  {$IFNDEF USEPAINTBOXPICTURE}
-  OnPaintHandler;
-  {$ENDIF}
+  UpdateToolbar;
 end;
 end;
 
 
 procedure TFMain.PictureSelectedLayerIndexChanged(sender: TLazPaintImage);
 procedure TFMain.PictureSelectedLayerIndexChanged(sender: TLazPaintImage);
@@ -4538,8 +4184,8 @@ end;
 procedure TFMain.SetShowSelectionNormal(const AValue: boolean);
 procedure TFMain.SetShowSelectionNormal(const AValue: boolean);
 begin
 begin
   FShowSelectionNormal := AValue;
   FShowSelectionNormal := AValue;
-  if Assigned(FImageView) then
-    FImageView.FillSelectionHighlight := ToolManager.DisplayFilledSelection and not FShowSelectionNormal;
+  if Assigned(FLayout) then
+    FLayout.FillSelectionHighlight := ToolManager.DisplayFilledSelection and not FShowSelectionNormal;
 end;
 end;
 
 
 procedure TFMain.WMEraseBkgnd(var Message: TLMEraseBkgnd);
 procedure TFMain.WMEraseBkgnd(var Message: TLMEraseBkgnd);
@@ -4673,8 +4319,8 @@ end;
 
 
 procedure TFMain.InvalidatePicture(AInvalidateAll: boolean = true);
 procedure TFMain.InvalidatePicture(AInvalidateAll: boolean = true);
 begin
 begin
-  if Assigned(FImageView) and Assigned(FLayout) then
-    FImageView.InvalidatePicture(AInvalidateAll, FLayout.WorkArea, Point(0,0), self);
+  if Assigned(FLayout) then
+    FLayout.InvalidatePicture(AInvalidateAll);
 end;
 end;
 
 
 function TFMain.GetUseImageBrowser: boolean;
 function TFMain.GetUseImageBrowser: boolean;
@@ -4695,15 +4341,8 @@ end;
 
 
 procedure TFMain.SetUpdatingPopup(AValue: boolean);
 procedure TFMain.SetUpdatingPopup(AValue: boolean);
 begin
 begin
-  FImageView.UpdatingPopup := AValue;
-end;
-
-function TFMain.GetCurrentPressure: single;
-begin
-  if Assigned(FTablet) and FTablet.Present and FTablet.Entering and (FTablet.Max > 0) then
-    result := FTablet.Pressure/FTablet.Max
-  else
-    result := 1;
+  if Assigned(FLayout) then
+    FLayout.UpdatingPopup := AValue;
 end;
 end;
 
 
 function TFMain.GetDarkTheme: boolean;
 function TFMain.GetDarkTheme: boolean;
@@ -4719,7 +4358,9 @@ end;
 
 
 function TFMain.GetUpdatingPopup: boolean;
 function TFMain.GetUpdatingPopup: boolean;
 begin
 begin
-  result := FImageView.UpdatingPopup;
+  if Assigned(FLayout) then
+    result := FLayout.UpdatingPopup
+    else result := false;
 end;
 end;
 
 
 function TFMain.GetScriptContext: TScriptContext;
 function TFMain.GetScriptContext: TScriptContext;
@@ -4741,15 +4382,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TFMain.PictureCanvasOfs: TPoint;
-begin
-  {$IFDEF USEPAINTBOXPICTURE}
-  result := Point(-PaintBox_Picture.Left,-PaintBox_Picture.Top);
-  {$ELSE}
-  result := Point(0,0);
-  {$ENDIF}
-end;
-
 {$R *.lfm}
 {$R *.lfm}
 
 
 end.
 end.

+ 7 - 0
lazpaint/lazpainttype.pas

@@ -181,6 +181,9 @@ type
     procedure SetBlackAndWhite(AValue: boolean); virtual;
     procedure SetBlackAndWhite(AValue: boolean); virtual;
     function GetZoomFactor: single; virtual;
     function GetZoomFactor: single; virtual;
 
 
+    function GetUpdateStackOnTimer: boolean; virtual; abstract;
+    procedure SetUpdateStackOnTimer(AValue: boolean); virtual; abstract;
+
     function GetChooseColorHeight: integer; virtual; abstract;
     function GetChooseColorHeight: integer; virtual; abstract;
     function GetChooseColorWidth: integer; virtual; abstract;
     function GetChooseColorWidth: integer; virtual; abstract;
     procedure SetChooseColorHeight(AValue: integer); virtual; abstract;
     procedure SetChooseColorHeight(AValue: integer); virtual; abstract;
@@ -241,6 +244,7 @@ type
     procedure CancelRestart; virtual; abstract;
     procedure CancelRestart; virtual; abstract;
     procedure NotifyImageChange(RepaintNow: boolean; ARect: TRect); virtual; abstract;
     procedure NotifyImageChange(RepaintNow: boolean; ARect: TRect); virtual; abstract;
     procedure NotifyImageChangeCompletely(RepaintNow: boolean); virtual; abstract;
     procedure NotifyImageChangeCompletely(RepaintNow: boolean); virtual; abstract;
+    procedure NotifyImagePaint; virtual; abstract;
     procedure NotifyStackChange; virtual; abstract;
     procedure NotifyStackChange; virtual; abstract;
     function TryOpenFileUTF8(filename: string; skipDialogIfSingleImage: boolean = false): boolean; virtual; abstract;
     function TryOpenFileUTF8(filename: string; skipDialogIfSingleImage: boolean = false): boolean; virtual; abstract;
     function ExecuteFilter(filter: TPictureFilter; skipDialog: boolean = false): TScriptResult; virtual; abstract;
     function ExecuteFilter(filter: TPictureFilter; skipDialog: boolean = false): TScriptResult; virtual; abstract;
@@ -294,6 +298,8 @@ type
     property BlackAndWhite: boolean read FBlackAndWhite write SetBlackAndWhite;
     property BlackAndWhite: boolean read FBlackAndWhite write SetBlackAndWhite;
 
 
     procedure ScrollLayerStackOnItem(AIndex: integer; ADelayedUpdate: boolean = true); virtual; abstract;
     procedure ScrollLayerStackOnItem(AIndex: integer; ADelayedUpdate: boolean = true); virtual; abstract;
+    procedure InvalidateLayerStack; virtual; abstract;
+    procedure UpdateLayerStackOnTimer; virtual; abstract;
     function MakeNewBitmapReplacement(AWidth, AHeight: integer; AColor: TBGRAPixel): TBGRABitmap; virtual; abstract;
     function MakeNewBitmapReplacement(AWidth, AHeight: integer; AColor: TBGRAPixel): TBGRABitmap; virtual; abstract;
     procedure ChooseTool(Tool : TPaintToolType); virtual; abstract;
     procedure ChooseTool(Tool : TPaintToolType); virtual; abstract;
     function GetOnlineUpdater: TLazPaintCustomOnlineUpdater; virtual;
     function GetOnlineUpdater: TLazPaintCustomOnlineUpdater; virtual;
@@ -340,6 +346,7 @@ type
     property Fullscreen: boolean read GetFullscreen write SetFullscreen;
     property Fullscreen: boolean read GetFullscreen write SetFullscreen;
     property RestartQuery: boolean read FRestartQuery;
     property RestartQuery: boolean read FRestartQuery;
     property DarkTheme: boolean read GetDarkTheme write SetDarkTheme;
     property DarkTheme: boolean read GetDarkTheme write SetDarkTheme;
+    property UpdateStackOnTimer: boolean read GetUpdateStackOnTimer write SetUpdateStackOnTimer;
 
 
     property Icons[ASize: integer]: TImageList read GetIcons;
     property Icons[ASize: integer]: TImageList read GetIcons;
   end;
   end;

+ 23 - 28
lazpaint/maintoolbar.inc

@@ -668,6 +668,27 @@ begin
   FInitialized := oldInit;
   FInitialized := oldInit;
 end;
 end;
 
 
+function TFMain.CatchToolKeyDown(var AKey: Word): boolean;
+begin
+  if Assigned(FLayout) then
+    result := FLayout.CatchToolKeyDown(AKey)
+    else result := false;
+end;
+
+function TFMain.CatchToolKeyUp(var AKey: Word): boolean;
+begin
+  if Assigned(FLayout) then
+    result := FLayout.CatchToolKeyUp(AKey)
+    else result := false;
+end;
+
+function TFMain.CatchToolKeyPress(var AKey: TUTF8Char): boolean;
+begin
+  if Assigned(FLayout) then
+    result := FLayout.CatchToolKeyPress(AKey)
+    else result := false;
+end;
+
 procedure TFMain.SpinEdit_ShapeAltitudeChange(Sender: TObject; AByUser: boolean);
 procedure TFMain.SpinEdit_ShapeAltitudeChange(Sender: TObject; AByUser: boolean);
 begin
 begin
   if SpinEdit_ShapeAltitude.Value < 6 then
   if SpinEdit_ShapeAltitude.Value < 6 then
@@ -1506,39 +1527,13 @@ begin
   if SpinEdit_PenWidth.Value < MinPenWidth*PenWidthFactor then SpinEdit_PenWidth.Value := MinPenWidth*PenWidthFactor;
   if SpinEdit_PenWidth.Value < MinPenWidth*PenWidthFactor then SpinEdit_PenWidth.Value := MinPenWidth*PenWidthFactor;
 end;
 end;
 
 
-procedure TFMain.IncreasePenSize;
-begin
-  SpinEdit_PenWidth.Value := max(SpinEdit_PenWidth.Value+PenSizeDelta(1),MinPenWidth*PenWidthFactor);
-  UpdatePenWidthFromSpinEdit;
-end;
-
-procedure TFMain.DecreasePenSize;
-begin
-  SpinEdit_PenWidth.Value := max(SpinEdit_PenWidth.Value-PenSizeDelta(-1),MinPenWidth*PenWidthFactor);
-  UpdatePenWidthFromSpinEdit;
-end;
-
-function TFMain.PenSizeDelta(direction: integer): integer;
-var v: integer;
-begin
-  v := SpinEdit_PenWidth.Value;
-  if direction < 0 then dec(v);
-  if v < 100 then result := 10 else
-  if v < 200 then result := 20 else
-  if v < 500 then result := 50 else
-  if v < 1000 then result := 100 else
-  if v < 2000 then result := 200 else
-  if v < 5000 then result := 500 else
-    result := 1000;
-end;
-
 procedure TFMain.PaintBox_PenPreviewMouseDown(Sender: TObject;
 procedure TFMain.PaintBox_PenPreviewMouseDown(Sender: TObject;
   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
 var t: integer;
 var t: integer;
 begin
 begin
   t := ImageList16.Width;
   t := ImageList16.Width;
-  if (X < t) and (Y < t) then DecreasePenSize else
-  if (X >= PaintBox_PenPreview.Width-t) and (Y < t) then IncreasePenSize;
+  if (X < t) and (Y < t) then ToolManager.StepPenSize(True) else
+  if (X >= PaintBox_PenPreview.Width-t) and (Y < t) then ToolManager.StepPenSize(False);
   ShowPenPreview(False);
   ShowPenPreview(False);
 end;
 end;
 
 

+ 21 - 0
lazpaint/tools/utool.pas

@@ -460,6 +460,7 @@ type
     function ApplyPressure(AOpacity: byte): byte;
     function ApplyPressure(AOpacity: byte): byte;
     procedure SetPressure(APressure: single);
     procedure SetPressure(APressure: single);
     function GetPressureB: Byte;
     function GetPressureB: Byte;
+    procedure StepPenSize(ADecrease: boolean);
 
 
     function GetCurrentToolType: TPaintToolType;
     function GetCurrentToolType: TPaintToolType;
     function SetCurrentToolType(tool: TPaintToolType): boolean;
     function SetCurrentToolType(tool: TPaintToolType): boolean;
@@ -3118,6 +3119,26 @@ begin
   result := round(FToolPressure*255);
   result := round(FToolPressure*255);
 end;
 end;
 
 
+procedure TToolManager.StepPenSize(ADecrease: boolean);
+  function SizeDelta: single;
+  var v: single;
+  begin
+    v := PenWidth;
+    if ADecrease then v := v - 0.1;
+    if v < 10 then result := 1 else
+    if v < 20 then result := 2 else
+    if v < 50 then result := 5 else
+    if v < 100 then result := 10 else
+    if v < 200 then result := 20 else
+    if v < 500 then result := 50 else
+      result := 100;
+  end;
+begin
+  if ADecrease then
+    PenWidth := PenWidth - SizeDelta
+    else PenWidth := PenWidth + SizeDelta;
+end;
+
 procedure TToolManager.InternalSetCurrentToolType(tool: TPaintToolType);
 procedure TToolManager.InternalSetCurrentToolType(tool: TPaintToolType);
 begin
 begin
   if (tool <> FCurrentToolType) or (FCurrentTool=nil) then
   if (tool <> FCurrentToolType) or (FCurrentTool=nil) then

+ 433 - 85
lazpaint/uimageview.pas

@@ -8,15 +8,20 @@ interface
 
 
 uses
 uses
   Classes, SysUtils, USelectionHighlight, BGRABitmap, BGRABitmapTypes,
   Classes, SysUtils, USelectionHighlight, BGRABitmap, BGRABitmapTypes,
-  LazPaintType, UImage, UZoom, Graphics, Controls;
+  LazPaintType, UImage, UZoom, Graphics, Controls, LCLType, UImageObservation,
+  laztablet;
 
 
 type
 type
+  TPictureMouseMoveEvent = procedure(ASender: TObject; APosition: TPointF) of object;
+  TPictureMouseBeforeEvent = procedure(ASender: TObject; AShift: TShiftState) of object;
 
 
   { TImageView }
   { TImageView }
 
 
   TImageView = class
   TImageView = class
+  private
+    function GetMouseButtonState: TShiftState;
   protected
   protected
-    FVirtualScreen : TBGRABitmap;
+    FVirtualScreen: TBGRABitmap;
     FUpdatingPopup: boolean;
     FUpdatingPopup: boolean;
     FPenCursorVisible: boolean;
     FPenCursorVisible: boolean;
     FPenCursorPos,FPenCursorPosBefore: TVSCursorPosition;
     FPenCursorPos,FPenCursorPosBefore: TVSCursorPosition;
@@ -35,33 +40,65 @@ type
        imageWidth,imageHeight: integer;
        imageWidth,imageHeight: integer;
     end;
     end;
     FZoom: TZoom;
     FZoom: TZoom;
-    FPictureCanvas: TCanvas;
+    FPaintBox: TGraphicControl;
+    FormMouseMovePos: TPoint;
+    InFormMouseMove: boolean;
+    InFormPaint: boolean;
+    FOnPaint: TNotifyEvent;
+    FOnToolbarUpdate: TNotifyEvent;
+    FOnMouseMove: TPictureMouseMoveEvent;
+    FOnMouseBefore: TPictureMouseBeforeEvent;
+    btnLeftDown, btnRightDown, btnMiddleDown: boolean;
+    FLastPaintDate: TDateTime;
+    FUpdateStackWhenIdle: boolean;
+    FCatchPaintPicture, FPaintPictureCatched: boolean;
+    InShowNoPicture: boolean;
+    FCanCompressOrUpdateStack: boolean;
+    FTablet: TLazTablet;
+    FImagePos: TPointF;
     function GetImage: TLazPaintImage;
     function GetImage: TLazPaintImage;
+    function GetPictureCanvas: TCanvas;
+    function GetWorkArea: TRect;
+    procedure PaintBoxMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+    procedure PaintBoxMouseEnter(Sender: TObject);
+    procedure PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
+    procedure PaintBoxMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+    procedure PaintBoxMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
+    procedure PaintBoxPaint(Sender: TObject);
+    procedure ImageChanged(AEvent: TLazPaintImageObservationEvent);
     function GetRenderUpdateRectVS(AIncludeCurrentToolEditor: boolean): TRect;
     function GetRenderUpdateRectVS(AIncludeCurrentToolEditor: boolean): TRect;
     function GetFillSelectionHighlight: boolean;
     function GetFillSelectionHighlight: boolean;
     function GetPenCursorPosition: TVSCursorPosition;
     function GetPenCursorPosition: TVSCursorPosition;
     function GetWorkspaceColor: TColor;
     function GetWorkspaceColor: TColor;
-    procedure PaintPictureImplementation(ACanvasOfs: TPoint; AWorkArea: TRect; AVSPart: TRect);
-    procedure PaintVirtualScreenImplementation(ACanvasOfs: TPoint; AWorkArea: TRect; AVSPart: TRect);
-    procedure PaintBlueAreaImplementation(ACanvasOfs: TPoint; AWorkArea: TRect);
-    procedure PaintBlueAreaOnly(ACanvasOfs: TPoint; AWorkArea: TRect);
+    procedure PaintPictureImplementation(AWorkArea: TRect; AVSPart: TRect);
+    procedure PaintVirtualScreenImplementation(AWorkArea: TRect; AVSPart: TRect);
+    procedure PaintBlueAreaImplementation(AWorkArea: TRect);
+    procedure PaintBlueAreaOnly(AWorkArea: TRect);
     procedure ComputePictureParams(AWorkArea: TRect);
     procedure ComputePictureParams(AWorkArea: TRect);
     procedure SetFillSelectionHighlight(AValue: boolean);
     procedure SetFillSelectionHighlight(AValue: boolean);
     procedure SetShowSelection(AValue: boolean);
     procedure SetShowSelection(AValue: boolean);
     procedure PictureSelectionChanged({%H-}sender: TLazPaintImage; const ARect: TRect);
     procedure PictureSelectionChanged({%H-}sender: TLazPaintImage; const ARect: TRect);
     procedure ToolManagerRenderChanged(Sender: TObject);
     procedure ToolManagerRenderChanged(Sender: TObject);
-    procedure PaintVirtualScreenCursor({%H-}ACanvasOfs: TPoint; {%H-}AWorkArea: TRect; {%H-}AWinControlOfs: TPoint; {%H-}AWinControl: TWinControl);
+    procedure PaintVirtualScreenCursor({%H-}AWorkArea: TRect);
     function GetRectToInvalidate(AInvalidateAll: boolean; AWorkArea: TRect): TRect;
     function GetRectToInvalidate(AInvalidateAll: boolean; AWorkArea: TRect): TRect;
     function GetPictureCoordsDefined: boolean;
     function GetPictureCoordsDefined: boolean;
+    procedure DoInvalidatePicture(AInvalidateAll: boolean; AWorkArea: TRect);
+    procedure DoPaint(AWorkArea: TRect; AShowNoPicture: boolean);
+    procedure DoUpdatePicture(AWorkArea: TRect);
+    procedure ReleaseMouseButtons(Shift: TShiftState);
+    function GetCurrentPressure: single;
   public
   public
-    constructor Create(AInstance: TLazPaintCustomInstance; AZoom: TZoom; ACanvas: TCanvas);
+    constructor Create(AInstance: TLazPaintCustomInstance; AZoom: TZoom; APaintBox: TGraphicControl);
     destructor Destroy; override;
     destructor Destroy; override;
-    procedure DoPaint(ACanvasOfs: TPoint; AWorkArea: TRect; AShowNoPicture: boolean);
-    procedure InvalidatePicture(AInvalidateAll: boolean; AWorkArea: TRect; AControlOfs: TPoint; AWinControl: TWinControl);
-    procedure OnZoomChanged({%H-}sender: TZoom; {%H-}ANewZoom: single; AWorkArea: TRect);
-    procedure UpdateCursor(X,Y: integer; ACanvasOfs: TPoint; AWorkArea: TRect; AControl: TControl;
-                          AWinControlOfs: TPoint; AWinControl: TWinControl);
-    procedure UpdatePicture({%H-}ACanvasOfs: TPoint; AWorkArea: TRect; {%H-}AWinControl: TWinControl);
+    function CatchToolKeyDown(var AKey: Word): boolean;
+    function CatchToolKeyPress(var AKey: TUTF8Char): boolean;
+    function CatchToolKeyUp(var AKey: Word): boolean;
+    procedure SetBounds(ALeft, ATop, AWidth, AHeight: integer);
+    procedure UpdatePicture;
+    procedure ShowNoPicture;
+    procedure InvalidatePicture(AInvalidateAll: boolean);
+    procedure OnZoomChanged({%H-}sender: TZoom; {%H-}ANewZoom: single);
+    procedure UpdateCursor(X,Y: integer);
     function BitmapToForm(pt: TPointF): TPointF;
     function BitmapToForm(pt: TPointF): TPointF;
     function BitmapToForm(X, Y: Single): TPointF;
     function BitmapToForm(X, Y: Single): TPointF;
     function BitmapToVirtualScreen(ptF: TPointF): TPointF;
     function BitmapToVirtualScreen(ptF: TPointF): TPointF;
@@ -71,17 +108,40 @@ type
     property Image: TLazPaintImage read GetImage;
     property Image: TLazPaintImage read GetImage;
     property Zoom: TZoom read FZoom;
     property Zoom: TZoom read FZoom;
     property LazPaintInstance: TLazPaintCustomInstance read FInstance;
     property LazPaintInstance: TLazPaintCustomInstance read FInstance;
-    property PictureCanvas: TCanvas read FPictureCanvas;
+    property PictureCanvas: TCanvas read GetPictureCanvas;
     property FillSelectionHighlight: boolean read GetFillSelectionHighlight write SetFillSelectionHighlight;
     property FillSelectionHighlight: boolean read GetFillSelectionHighlight write SetFillSelectionHighlight;
     property ShowSelection: boolean read FShowSelection write SetShowSelection;
     property ShowSelection: boolean read FShowSelection write SetShowSelection;
     property WorkspaceColor: TColor read GetWorkspaceColor;
     property WorkspaceColor: TColor read GetWorkspaceColor;
+    property WorkArea: TRect read GetWorkArea;
     property PictureCoordsDefined: boolean read GetPictureCoordsDefined;
     property PictureCoordsDefined: boolean read GetPictureCoordsDefined;
     property UpdatingPopup: boolean read FUpdatingPopup write FUpdatingPopup;
     property UpdatingPopup: boolean read FUpdatingPopup write FUpdatingPopup;
+    property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
+    property OnMouseMove: TPictureMouseMoveEvent read FOnMouseMove write FOnMouseMove;
+    property OnMouseBefore: TPictureMouseBeforeEvent read FOnMouseBefore write FOnMouseBefore;
+    property OnToolbarUpdate: TNotifyEvent read FOnToolbarUpdate write FOnToolbarUpdate;
+    property LastPaintDate: TDateTime read FLastPaintDate;
+    property MouseButtonState: TShiftState read GetMouseButtonState;
+    property CanCompressOrUpdateStack: boolean read FCanCompressOrUpdateStack;
   end;
   end;
 
 
 implementation
 implementation
 
 
-uses BGRATransform, LCLIntf, Types, ugraph, math, UTool, BGRAThumbnail, LCScaleDPI;
+uses BGRATransform, LCLIntf, Types, ugraph, math, UTool, BGRAThumbnail, LCScaleDPI, Forms,
+  UToolVectorial, ExtCtrls;
+
+procedure InvalidateControlRect(AControl: TControl; AArea: TRect);
+var
+  h: HWND;
+begin
+  if AControl is TWinControl then
+    h := TWinControl(AControl).Handle
+  else
+  begin
+    AArea.Offset(AControl.Left, AControl.Top);
+    h := AControl.Parent.Handle;
+  end;
+  InvalidateRect(h, @AArea, False);
+end;
 
 
 function TImageView.GetFillSelectionHighlight: boolean;
 function TImageView.GetFillSelectionHighlight: boolean;
 begin
 begin
@@ -119,12 +179,185 @@ begin
                             FVirtualScreen.Width, FVirtualScreen.Height));
                             FVirtualScreen.Width, FVirtualScreen.Height));
 end;
 end;
 
 
+procedure TImageView.PaintBoxMouseEnter(Sender: TObject);
+begin
+  Image.PrepareForRendering;
+end;
+
+procedure TImageView.PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
+  Y: Integer);
+var
+  updateForVSCursor: boolean;
+begin
+  if Assigned(FOnMouseBefore) then
+    FOnMouseBefore(self, Shift);
+  ReleaseMouseButtons(Shift);
+  Image.CurrentState.LayeredBitmap.EditorFocused := true;
+
+  FormMouseMovePos := Point(X,Y);
+  if InFormMouseMove then exit;
+  InFormMouseMove := True;
+  if not PictureCoordsDefined then
+    Application.ProcessMessages; //empty message stack
+  if not PictureCoordsDefined then
+  begin
+    InFormMouseMove:= false;
+    exit;
+  end;
+
+  FImagePos := FormToBitmap(FormMouseMovePos);
+  if Assigned(FOnMouseMove) then
+    FOnMouseMove(self, FImagePos);
+
+  updateForVSCursor:= false;
+  if LazPaintInstance.ToolManager.ToolMove(FImagePos, GetCurrentPressure) then
+    UpdatePicture
+  else
+    updateForVSCursor := true;
+  if Assigned(FOnToolbarUpdate) then
+    FOnToolbarUpdate(self);
+
+  if updateForVSCursor then
+    UpdateCursor(X,Y);
+
+  InFormMouseMove := False;
+end;
+
+procedure TImageView.PaintBoxMouseUp(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+var redraw: boolean;
+begin
+  redraw := false;
+  if (btnLeftDown and (Button = mbLeft)) or (btnRightDown and (Button=mbRight))
+    or (btnMiddleDown and (Button = mbMiddle)) then
+  begin
+    if PictureCoordsDefined then
+      redraw := LazPaintInstance.ToolManager.ToolMove(FormToBitmap(X,Y), GetCurrentPressure)
+      else redraw := false;
+    if LazPaintInstance.ToolManager.ToolUp then redraw := true;
+    btnLeftDown := false;
+    btnRightDown := false;
+    btnMiddleDown:= false;
+  end;
+  if redraw then UpdatePicture;
+  if FUpdateStackWhenIdle then
+  begin
+    LazPaintInstance.UpdateLayerStackOnTimer;
+    FUpdateStackWhenIdle:= false;
+  end;
+  if Assigned(FOnToolbarUpdate) then
+    FOnToolbarUpdate(self);
+  ReleaseMouseButtons(Shift);
+end;
+
+procedure TImageView.PaintBoxMouseWheel(Sender: TObject; Shift: TShiftState;
+  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
+begin
+  if not PictureCoordsDefined then exit;
+  if ssAlt in Shift then
+  begin
+    if WheelDelta > 0 then LazPaintInstance.ToolManager.StepPenSize(false)
+    else if WheelDelta < 0 then LazPaintInstance.ToolManager.StepPenSize(true);
+  end else
+  begin
+    Zoom.SetPosition(FormToBitmap(MousePos.X,MousePos.Y), MousePos);
+    if WheelDelta > 0 then Zoom.ZoomIn(ssSnap in Shift) else
+    if WheelDelta < 0 then Zoom.ZoomOut(ssSnap in Shift);
+    Zoom.ClearPosition;
+  end;
+  Handled := True;
+end;
+
+procedure TImageView.PaintBoxMouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+begin
+  ReleaseMouseButtons(Shift);
+  if not (Button in[mbLeft,mbRight,mbMiddle]) or not PictureCoordsDefined then exit;
+  FCanCompressOrUpdateStack := false;
+  if Assigned(LazPaintInstance) then LazPaintInstance.ExitColorEditor;
+  Image.OnImageChanged.DelayedStackUpdate := True;
+
+  if btnLeftDown or btnRightDown or btnMiddleDown then exit;
+
+  if Button = mbMiddle then
+  begin
+    btnMiddleDown:= true;
+    if not LazPaintInstance.ToolManager.ToolSleeping and not (ssAlt in Shift) then LazPaintInstance.ToolManager.ToolSleep;
+  end;
+
+  if PictureCoordsDefined then
+  begin
+    if Button = mbLeft then
+      btnLeftDown := true else
+    if Button = mbRight then
+      btnRightDown := true;
+
+    with LazPaintInstance.ToolManager do
+    begin
+      if (
+          (GetCurrentToolType = ptHand) or
+          ((GetCurrentToolType = ptEditShape) and
+            Assigned(CurrentTool) and
+            (CurrentTool as TEditShapeTool).NothingSelected)
+         )  and
+         (ssShift in Shift) then
+        Image.SelectLayerContainingPixelAt(FormToBitmap(X,Y).Round);
+
+      if ToolDown(FormToBitmap(X,Y),
+          btnRightDown{$IFDEF DARWIN} or (ssCtrl in Shift){$ENDIF},
+          GetCurrentPressure) then
+          UpdatePicture;
+    end;
+
+    if Assigned(FOnToolbarUpdate) then
+      FOnToolbarUpdate(self);
+  end;
+end;
+
+function TImageView.GetPictureCanvas: TCanvas;
+begin
+  result := FPaintBox.Canvas;
+end;
+
+procedure TImageView.PaintBoxPaint(Sender: TObject);
+begin
+  if InFormPaint then exit;
+  InFormPaint := true;
+
+  DoPaint(WorkArea, InShowNoPicture);
+  LazPaintInstance.NotifyImagePaint;
+
+  InFormPaint := false;
+  FLastPaintDate := Now;
+end;
+
+function TImageView.GetWorkArea: TRect;
+begin
+  result := rect(0, 0, FPaintBox.Width, FPaintBox.Height);
+end;
+
+procedure TImageView.ImageChanged(AEvent: TLazPaintImageObservationEvent);
+begin
+  if AEvent.DelayedStackUpdate then FUpdateStackWhenIdle := true;
+  if FCatchPaintPicture then
+    FPaintPictureCatched := true
+    else InvalidatePicture(false);
+end;
+
+function TImageView.GetMouseButtonState: TShiftState;
+begin
+  result := [];
+  if btnLeftDown then include(result, ssLeft);
+  if btnMiddleDown then include(result, ssMiddle);
+  if btnRightDown then include(result, ssRight);
+end;
+
 function TImageView.GetImage: TLazPaintImage;
 function TImageView.GetImage: TLazPaintImage;
 begin
 begin
   result := FInstance.Image;
   result := FInstance.Image;
 end;
 end;
 
 
-procedure TImageView.PaintPictureImplementation(ACanvasOfs: TPoint; AWorkArea: TRect; AVSPart: TRect);
+procedure TImageView.PaintPictureImplementation(AWorkArea: TRect; AVSPart: TRect);
 var
 var
   renderRect: TRect;
   renderRect: TRect;
   picParamWereDefined: boolean;
   picParamWereDefined: boolean;
@@ -204,23 +437,24 @@ begin
     Image.RenderMayChange(LazPaintInstance.ToolManager.RenderTool(FVirtualScreen), false, false);
     Image.RenderMayChange(LazPaintInstance.ToolManager.RenderTool(FVirtualScreen), false, false);
   end;
   end;
 
 
-  PaintVirtualScreenImplementation(ACanvasOfs, AWorkArea, AVSPart);
+  PaintVirtualScreenImplementation(AWorkArea, AVSPart);
   Image.VisibleArea := TRectF.Intersect(rectF(FormToBitmap(AWorkArea.Left, AWorkArea.Top),
   Image.VisibleArea := TRectF.Intersect(rectF(FormToBitmap(AWorkArea.Left, AWorkArea.Top),
                                               FormToBitmap(AWorkArea.Right, AWorkArea.Bottom)),
                                               FormToBitmap(AWorkArea.Right, AWorkArea.Bottom)),
                           rectF(-0.5,-0.5,Image.Width-0.5,Image.Height-0.5));
                           rectF(-0.5,-0.5,Image.Width-0.5,Image.Height-0.5));
 end;
 end;
 
 
-procedure TImageView.PaintVirtualScreenImplementation(ACanvasOfs: TPoint; AWorkArea: TRect; AVSPart: TRect);
+procedure TImageView.PaintVirtualScreenImplementation(AWorkArea: TRect; AVSPart: TRect);
 var cursorBack: TBGRABitmap;
 var cursorBack: TBGRABitmap;
     DestCanvas: TCanvas;
     DestCanvas: TCanvas;
-    DrawOfs: TPoint;
     cursorContourF: array of TPointF;
     cursorContourF: array of TPointF;
     rectBack: TRect;
     rectBack: TRect;
     cursorPos: TVSCursorPosition;
     cursorPos: TVSCursorPosition;
 
 
   procedure DrawPart;
   procedure DrawPart;
   begin
   begin
-    FVirtualScreen.DrawPart(AVSPart, DestCanvas, DrawOfs.X+AVSPart.Left, DrawOfs.Y+AVSPart.Top, True);
+    FVirtualScreen.DrawPart(AVSPart, DestCanvas,
+      FLastPictureParameters.virtualScreenArea.Left+AVSPart.Left,
+      FLastPictureParameters.virtualScreenArea.Top+AVSPart.Top, True);
   end;
   end;
 
 
 begin
 begin
@@ -229,9 +463,6 @@ begin
   if AVSPart.IsEmpty then exit;
   if AVSPart.IsEmpty then exit;
 
 
   DestCanvas := PictureCanvas;
   DestCanvas := PictureCanvas;
-  DrawOfs := ACanvasOfs;
-  Inc(DrawOfs.X, FLastPictureParameters.virtualScreenArea.Left);
-  inc(DrawOfs.Y, FLastPictureParameters.virtualScreenArea.Top);
 
 
   cursorPos := FPenCursorPos;
   cursorPos := FPenCursorPos;
   if FPenCursorVisible and not IsRectEmpty(cursorPos.bounds) then
   if FPenCursorVisible and not IsRectEmpty(cursorPos.bounds) then
@@ -263,88 +494,177 @@ begin
     Zoom.MaxFactor := min(32,max(1,min((right-left)/8,(bottom-top)/8)));
     Zoom.MaxFactor := min(32,max(1,min((right-left)/8,(bottom-top)/8)));
 end;
 end;
 
 
-procedure TImageView.PaintBlueAreaImplementation(ACanvasOfs: TPoint; AWorkArea: TRect);
+procedure TImageView.PaintBlueAreaImplementation(AWorkArea: TRect);
 var
 var
-  DrawOfs: TPoint;
-  workArea, scaledArea: TRect;
+  lastWorkArea, scaledArea: TRect;
 begin
 begin
   if FLastPictureParameters.defined then
   if FLastPictureParameters.defined then
   begin
   begin
-    workArea := FLastPictureParameters.workArea;
-    if (workArea.Right <= workArea.Left) or (workArea.Bottom <= workArea.Top) then exit;
+    lastWorkArea := FLastPictureParameters.WorkArea;
+    if (lastWorkArea.Right <= lastWorkArea.Left) or (lastWorkArea.Bottom <= lastWorkArea.Top) then exit;
     scaledArea := FLastPictureParameters.scaledArea;
     scaledArea := FLastPictureParameters.scaledArea;
-    IntersectRect(scaledArea, scaledArea,workArea);
+    IntersectRect(scaledArea, scaledArea,lastWorkArea);
     with PictureCanvas do
     with PictureCanvas do
     begin
     begin
       Brush.Color := WorkspaceColor;
       Brush.Color := WorkspaceColor;
-      DrawOfs := ACanvasOfs;
-      if scaledArea.Left > workArea.Left then
-        FillRect(workArea.Left+DrawOfs.X,scaledArea.Top+DrawOfs.Y,scaledArea.Left+DrawOfs.X,scaledArea.Bottom+DrawOfs.Y);
-      if scaledArea.Top > workArea.Top then
-        FillRect(workArea.Left+DrawOfs.X,workArea.Top+DrawOfs.Y,workArea.Right+DrawOfs.X,scaledArea.Top+DrawOfs.Y);
-      if scaledArea.Right < workArea.Right then
-        FillRect(scaledArea.Right+DrawOfs.X,scaledArea.Top+DrawOfs.Y,workArea.Right+DrawOfs.X,scaledArea.Bottom+DrawOfs.Y);
-      if scaledArea.Bottom < workArea.Bottom then
-        FillRect(workArea.Left+DrawOfs.X,scaledArea.Bottom+DrawOfs.Y,workArea.Right+DrawOfs.X,workArea.Bottom+DrawOfs.Y);
+      if scaledArea.Left > lastWorkArea.Left then
+        FillRect(lastWorkArea.Left, scaledArea.Top, scaledArea.Left, scaledArea.Bottom);
+      if scaledArea.Top > lastWorkArea.Top then
+        FillRect(lastWorkArea.Left, lastWorkArea.Top, lastWorkArea.Right, scaledArea.Top);
+      if scaledArea.Right < lastWorkArea.Right then
+        FillRect(scaledArea.Right, scaledArea.Top, lastWorkArea.Right, scaledArea.Bottom);
+      if scaledArea.Bottom < lastWorkArea.Bottom then
+        FillRect(lastWorkArea.Left, scaledArea.Bottom, lastWorkArea.Right, lastWorkArea.Bottom);
     end;
     end;
   end else
   end else
-    PaintBlueAreaOnly(ACanvasOfs, AWorkArea);
+    PaintBlueAreaOnly(AWorkArea);
 end;
 end;
 
 
-procedure TImageView.PaintBlueAreaOnly(ACanvasOfs: TPoint; AWorkArea: TRect);
-var
-  DrawOfs: TPoint;
+procedure TImageView.PaintBlueAreaOnly(AWorkArea: TRect);
 begin
 begin
   if (AWorkArea.Right <= AWorkArea.Left) or (AWorkArea.Bottom <= AWorkArea.Top) then exit;
   if (AWorkArea.Right <= AWorkArea.Left) or (AWorkArea.Bottom <= AWorkArea.Top) then exit;
   with PictureCanvas do
   with PictureCanvas do
   begin
   begin
     Brush.Color := WorkspaceColor;
     Brush.Color := WorkspaceColor;
-    DrawOfs := ACanvasOfs;
-    FillRect(AWorkArea.Left+DrawOfs.X,AWorkArea.Top+DrawOfs.Y,AWorkArea.Right+DrawOfs.X,AWorkArea.Bottom+DrawOfs.Y);
+    FillRect(AWorkArea);
   end;
   end;
   FLastPictureParameters.defined := false;
   FLastPictureParameters.defined := false;
 end;
 end;
 
 
 constructor TImageView.Create(AInstance: TLazPaintCustomInstance; AZoom: TZoom;
 constructor TImageView.Create(AInstance: TLazPaintCustomInstance; AZoom: TZoom;
-  ACanvas: TCanvas);
+  APaintBox: TGraphicControl);
 begin
 begin
   FInstance := AInstance;
   FInstance := AInstance;
   FZoom := AZoom;
   FZoom := AZoom;
-  FPictureCanvas := ACanvas;
 
 
-  FVirtualScreen := nil;
+  FPaintBox := APaintBox;
+  (FPaintBox as TPaintBox).OnMouseEnter:=@PaintBoxMouseEnter;
+  (FPaintBox as TPaintBox).OnMouseDown:= @PaintBoxMouseDown;
+  (FPaintBox as TPaintBox).OnMouseMove:= @PaintBoxMouseMove;
+  (FPaintBox as TPaintBox).OnMouseUp:=   @PaintBoxMouseUp;
+  (FPaintBox as TPaintBox).OnMouseWheel:=@PaintBoxMouseWheel;
+  (FPaintBox as TPaintBox).OnPaint:=@PaintBoxPaint;
+  //recursive calls
+  InFormMouseMove:= false;
+  InFormPaint := false;
   FLastPictureParameters.defined:= false;
   FLastPictureParameters.defined:= false;
   FSelectionHighlight := TSelectionHighlight.Create(Image);
   FSelectionHighlight := TSelectionHighlight.Create(Image);
   FShowSelection:= true;
   FShowSelection:= true;
   Image.OnSelectionChanged := @PictureSelectionChanged;
   Image.OnSelectionChanged := @PictureSelectionChanged;
-  LazPaintInstance.ToolManager.OnToolRenderChanged:=@ToolManagerRenderChanged;
-  LazPaintInstance.ToolManager.BitmapToVirtualScreen := @BitmapToVirtualScreen;
+  Image.OnImageChanged.AddObserver(@ImageChanged);
+  if Assigned(LazPaintInstance.ToolManager) then
+  begin
+    LazPaintInstance.ToolManager.OnToolRenderChanged:=@ToolManagerRenderChanged;
+    LazPaintInstance.ToolManager.BitmapToVirtualScreen := @BitmapToVirtualScreen;
+  end;
+
+  //mouse status
+  btnLeftDown := false;
+  btnRightDown := false;
+  btnMiddleDown:= false;
+  FImagePos := EmptyPointF;
+  try
+    FTablet := TLazTablet.Create(nil);
+  except
+    on ex: exception do
+      FTablet := nil;
+  end;
 end;
 end;
 
 
 destructor TImageView.Destroy;
 destructor TImageView.Destroy;
 begin
 begin
+  FreeAndNil(FTablet);
   if Assigned(LazPaintInstance.ToolManager) then
   if Assigned(LazPaintInstance.ToolManager) then
+  begin
+    LazPaintInstance.ToolManager.OnToolRenderChanged := nil;
     LazPaintInstance.ToolManager.BitmapToVirtualScreen := nil;
     LazPaintInstance.ToolManager.BitmapToVirtualScreen := nil;
+  end;
+  Image.OnImageChanged.RemoveObserver(@ImageChanged);
   Image.OnSelectionChanged := nil;
   Image.OnSelectionChanged := nil;
   FreeAndNil(FSelectionHighlight);
   FreeAndNil(FSelectionHighlight);
   FreeAndNil(FVirtualScreen);
   FreeAndNil(FVirtualScreen);
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-procedure TImageView.DoPaint(ACanvasOfs: TPoint; AWorkArea: TRect; AShowNoPicture: boolean);
+procedure TImageView.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
+var picBoundsChanged: boolean;
+begin
+  picBoundsChanged := (FPaintBox.Left <> ALeft) or (FPaintBox.Top <> ATop) or
+      (FPaintBox.Width <> AWidth) or (FPaintBox.Height <> AHeight);
+  FPaintBox.SetBounds(ALeft, ATop, AWidth, AHeight);
+  if picBoundsChanged then
+    InvalidatePicture(True);
+end;
+
+function TImageView.CatchToolKeyDown(var AKey: Word): boolean;
 begin
 begin
-   if AShowNoPicture then
-   begin
-     PaintBlueAreaOnly(ACanvasOfs, AWorkArea);
-     exit;
-   end;
-   if FQueryPaintVirtualScreen and
-      (FLastPictureParameters.defined and
-       IsRectEmpty(GetRenderUpdateRectVS(False))) then
-     PaintVirtualScreenImplementation(ACanvasOfs, AWorkArea, rect(0,0,maxLongint,maxLongint))
-   else
-     PaintPictureImplementation(ACanvasOfs, AWorkArea, rect(0,0,maxLongint,maxLongint));
-   PaintBlueAreaImplementation(ACanvasOfs, AWorkArea);
+  FCatchPaintPicture:= true;
+  FPaintPictureCatched := false;
+  try
+    result := LazPaintInstance.ToolManager.ToolKeyDown(AKey) or FPaintPictureCatched;
+  finally
+    FCatchPaintPicture:= false;
+  end;
+end;
+
+function TImageView.CatchToolKeyUp(var AKey: Word): boolean;
+begin
+  FCatchPaintPicture:= true;
+  FPaintPictureCatched := false;
+  try
+     result := LazPaintInstance.ToolManager.ToolKeyUp(AKey) or FPaintPictureCatched;
+  finally
+    FCatchPaintPicture:= false;
+  end;
+end;
+
+function TImageView.CatchToolKeyPress(var AKey: TUTF8Char): boolean;
+begin
+  FCatchPaintPicture:= true;
+  FPaintPictureCatched := false;
+  try
+    result := LazPaintInstance.ToolManager.ToolKeyPress(AKey) or FPaintPictureCatched;
+  finally
+    FCatchPaintPicture:= false;
+  end;
+end;
+
+procedure TImageView.UpdatePicture;
+begin
+  DoUpdatePicture(WorkArea);
+  if not Image.OnImageChanged.DelayedStackUpdate then LazPaintInstance.InvalidateLayerStack;
+end;
+
+procedure TImageView.ShowNoPicture;
+begin
+  InShowNoPicture := true;
+  try
+    DoUpdatePicture(WorkArea);
+  finally
+    InShowNoPicture := false;
+  end;
+end;
+
+procedure TImageView.DoPaint(AWorkArea: TRect; AShowNoPicture: boolean);
+begin
+  if AShowNoPicture then
+    PaintBlueAreaOnly(AWorkArea)
+  else
+  begin
+    if FQueryPaintVirtualScreen and
+       (FLastPictureParameters.defined and
+        IsRectEmpty(GetRenderUpdateRectVS(False))) then
+       PaintVirtualScreenImplementation(AWorkArea, rect(0,0,maxLongint,maxLongint))
+    else
+      PaintPictureImplementation(AWorkArea, rect(0,0,maxLongint,maxLongint));
+    PaintBlueAreaImplementation(AWorkArea);
+  end;
+  if Assigned(FOnPaint) then FOnPaint(self);
+end;
+
+procedure TImageView.InvalidatePicture(AInvalidateAll: boolean);
+begin
+  DoInvalidatePicture(AInvalidateAll, WorkArea);
 end;
 end;
 
 
 procedure TImageView.ComputePictureParams(AWorkArea: TRect);
 procedure TImageView.ComputePictureParams(AWorkArea: TRect);
@@ -386,13 +706,13 @@ begin
   FLastPictureParameters.defined := true;
   FLastPictureParameters.defined := true;
 end;
 end;
 
 
-procedure TImageView.OnZoomChanged(sender: TZoom; ANewZoom: single; AWorkArea: TRect);
+procedure TImageView.OnZoomChanged(sender: TZoom; ANewZoom: single);
 Var
 Var
   NewBitmapPos: TPointF;
   NewBitmapPos: TPointF;
 begin
 begin
   if sender.PositionDefined then
   if sender.PositionDefined then
   begin
   begin
-    ComputePictureParams(AWorkArea);
+    ComputePictureParams(WorkArea);
     NewBitmapPos := FormToBitmap(sender.MousePosition.X,sender.MousePosition.Y);
     NewBitmapPos := FormToBitmap(sender.MousePosition.X,sender.MousePosition.Y);
     image.ImageOffset:= point(image.ImageOffset.X + round(NewBitmapPos.X-sender.BitmapPosition.X),
     image.ImageOffset:= point(image.ImageOffset.X + round(NewBitmapPos.X-sender.BitmapPosition.X),
                               image.ImageOffset.Y + round(NewBitmapPos.Y-sender.BitmapPosition.Y));
                               image.ImageOffset.Y + round(NewBitmapPos.Y-sender.BitmapPosition.Y));
@@ -486,14 +806,13 @@ begin
     result.bounds := EmptyRect;
     result.bounds := EmptyRect;
 end;
 end;
 
 
-procedure TImageView.InvalidatePicture(AInvalidateAll: boolean; AWorkArea: TRect; AControlOfs: TPoint; AWinControl: TWinControl);
+procedure TImageView.DoInvalidatePicture(AInvalidateAll: boolean; AWorkArea: TRect);
 var
 var
   area: TRect;
   area: TRect;
 begin
 begin
   area := GetRectToInvalidate(AInvalidateAll, AWorkArea);
   area := GetRectToInvalidate(AInvalidateAll, AWorkArea);
   IntersectRect(area, area, AWorkArea);
   IntersectRect(area, area, AWorkArea);
-  OffsetRect(area, AControlOfs.X,AControlOfs.Y);
-  InvalidateRect(AWinControl.Handle,@area,False);
+  InvalidateControlRect(FPaintBox, area);
 end;
 end;
 
 
 procedure TImageView.PictureSelectionChanged(sender: TLazPaintImage; const ARect: TRect);
 procedure TImageView.PictureSelectionChanged(sender: TLazPaintImage; const ARect: TRect);
@@ -501,8 +820,7 @@ begin
   if Assigned(FSelectionHighlight) then FSelectionHighlight.NotifyChange(ARect);
   if Assigned(FSelectionHighlight) then FSelectionHighlight.NotifyChange(ARect);
 end;
 end;
 
 
-procedure TImageView.PaintVirtualScreenCursor(ACanvasOfs: TPoint; AWorkArea: TRect;
-                                              AWinControlOfs: TPoint; AWinControl: TWinControl);
+procedure TImageView.PaintVirtualScreenCursor(AWorkArea: TRect);
 var area: TRect;
 var area: TRect;
 begin
 begin
   area := FPenCursorPos.bounds;
   area := FPenCursorPos.bounds;
@@ -512,12 +830,11 @@ begin
                    FLastPictureParameters.virtualScreenArea.Top);
                    FLastPictureParameters.virtualScreenArea.Top);
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}
   OffsetRect(area, -FLastPictureParameters.virtualScreenArea.Left, -FLastPictureParameters.virtualScreenArea.Top);
   OffsetRect(area, -FLastPictureParameters.virtualScreenArea.Left, -FLastPictureParameters.virtualScreenArea.Top);
-  PaintVirtualScreenImplementation(ACanvasOfs, AWorkArea, area);
+  PaintVirtualScreenImplementation(AWorkArea, area);
   {$ELSE}
   {$ELSE}
   FQueryPaintVirtualScreen := True;
   FQueryPaintVirtualScreen := True;
-  OffsetRect(area, AWinControlOfs.X,AWinControlOfs.Y);
-  InvalidateRect(AWinControl.Handle,@area,False);
-  AWinControl.Update;
+  InvalidateControlRect(FPaintBox, area);
+  FPaintBox.Update;
   FQueryPaintVirtualScreen := False;
   FQueryPaintVirtualScreen := False;
   {$ENDIF}
   {$ENDIF}
 end;
 end;
@@ -544,8 +861,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TImageView.UpdateCursor(X,Y: integer; ACanvasOfs: TPoint; AWorkArea: TRect; AControl: TControl;
-                                 AWinControlOfs: TPoint; AWinControl: TWinControl);
+procedure TImageView.UpdateCursor(X,Y: integer);
 var virtualScreenPenCursorBefore: boolean;
 var virtualScreenPenCursorBefore: boolean;
     wantedCursor: TCursor;
     wantedCursor: TCursor;
 
 
@@ -567,13 +883,13 @@ begin
   FPenCursorVisible := false;
   FPenCursorVisible := false;
   wantedCursor := LazPaintInstance.ToolManager.Cursor;
   wantedCursor := LazPaintInstance.ToolManager.Cursor;
   if LazPaintInstance.ToolManager.GetCurrentToolType in[ptPen,ptEraser,ptBrush,ptClone] then UseVSPenCursor;
   if LazPaintInstance.ToolManager.GetCurrentToolType in[ptPen,ptEraser,ptBrush,ptClone] then UseVSPenCursor;
-  if not PtInRect(AWorkArea, Point(X,Y)) then wantedCursor:= crDefault;
-  if AControl.Cursor <> wantedCursor then AControl.Cursor := wantedCursor;
+  if not PtInRect(WorkArea, Point(X,Y)) then wantedCursor:= crDefault;
+  if FPaintBox.Cursor <> wantedCursor then FPaintBox.Cursor := wantedCursor;
   if virtualScreenPenCursorBefore or FPenCursorVisible then
   if virtualScreenPenCursorBefore or FPenCursorVisible then
-    PaintVirtualScreenCursor(ACanvasOfs, AWorkArea, AWinControlOfs, AWinControl);
+    PaintVirtualScreenCursor(WorkArea);
 end;
 end;
 
 
-procedure TImageView.UpdatePicture(ACanvasOfs: TPoint; AWorkArea: TRect; AWinControl: TWinControl);
+procedure TImageView.DoUpdatePicture(AWorkArea: TRect);
 var
 var
   updateArea: TRect;
   updateArea: TRect;
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}prevVSArea: TRect;{$ENDIF}
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}prevVSArea: TRect;{$ENDIF}
@@ -588,17 +904,49 @@ begin
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}
   if FLastPictureParameters.defined then
   if FLastPictureParameters.defined then
     OffsetRect(updateArea, -FLastPictureParameters.virtualScreenArea.Left,-FLastPictureParameters.virtualScreenArea.Top);
     OffsetRect(updateArea, -FLastPictureParameters.virtualScreenArea.Left,-FLastPictureParameters.virtualScreenArea.Top);
-  PaintPictureImplementation(ACanvasOfs, AWorkArea, updateArea);
+  PaintPictureImplementation(AWorkArea, updateArea);
   if prevVSArea <> FLastPictureParameters.virtualScreenArea then
   if prevVSArea <> FLastPictureParameters.virtualScreenArea then
-    PaintBlueAreaImplementation(ACanvasOfs, AWorkArea);
+    PaintBlueAreaImplementation(AWorkArea);
   {$ELSE}
   {$ELSE}
   if IntersectRect(updateArea, updateArea, AWorkArea) then
   if IntersectRect(updateArea, updateArea, AWorkArea) then
   begin
   begin
-    InvalidateRect(AWinControl.Handle, @updateArea, false);
-    AWinControl.Update;
+    InvalidateControlRect(FPaintBox, updateArea);
+    FPaintBox.Update;
   end;
   end;
   {$ENDIF}
   {$ENDIF}
 end;
 end;
 
 
+procedure TImageView.ReleaseMouseButtons(Shift: TShiftState);
+begin
+  if not (ssLeft in Shift) and btnLeftDown then
+  begin
+    btnLeftDown := false;
+    if LazPaintInstance.ToolManager.ToolUp then UpdatePicture;
+  end;
+  if not (ssRight in Shift) and btnRightDown then
+  begin
+    btnRightDown := false;
+    if LazPaintInstance.ToolManager.ToolUp then UpdatePicture;
+  end;
+  if not (ssMiddle in Shift) and btnMiddleDown then
+  begin
+    btnMiddleDown := false;
+    if LazPaintInstance.ToolManager.ToolUp then UpdatePicture;
+  end;
+  if not btnLeftDown and not btnRightDown then
+  begin
+    FCanCompressOrUpdateStack := true;
+    Image.OnImageChanged.DelayedStackUpdate := False;
+  end;
+end;
+
+function TImageView.GetCurrentPressure: single;
+begin
+  if Assigned(FTablet) and FTablet.Present and FTablet.Entering and (FTablet.Max > 0) then
+    result := FTablet.Pressure/FTablet.Max
+  else
+    result := 1;
+end;
+
 end.
 end.
 
 

+ 194 - 31
lazpaint/umainformlayout.pas

@@ -6,8 +6,10 @@ unit UMainFormLayout;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, UMenu, Forms, LazPaintType, UZoom, ExtCtrls, ComCtrls,
-  Menus, UPaletteToolbar, BGRABitmapTypes, Controls;
+  Classes, LCLType, SysUtils, UMenu, Forms, LazPaintType, UZoom, ExtCtrls, ComCtrls,
+  Menus, UPaletteToolbar, BGRABitmapTypes, Controls, UImageView;
+
+const SelectionPaintDelay = 100/(1000*60*60*24);
 
 
 type
 type
   TOnPictureAreaChange = procedure(ASender: TObject; ANewArea: TRect) of object;
   TOnPictureAreaChange = procedure(ASender: TObject; ANewArea: TRect) of object;
@@ -18,12 +20,15 @@ type
   { TMainFormLayout }
   { TMainFormLayout }
 
 
   TMainFormLayout = class(TCustomMainFormLayout)
   TMainFormLayout = class(TCustomMainFormLayout)
-    procedure PaletteVisibilityChangedByUser(Sender: TObject);
   private
   private
     FForm: TForm;
     FForm: TForm;
+    FOnPaintPicture: TNotifyEvent;
+    FOnPictureMouseBefore: TPictureMouseBeforeEvent;
+    FOnPictureMouseMove: TPictureMouseMoveEvent;
+    FOnToolbarUpdate: TNotifyEvent;
+    FZoom: TZoom;
     FMenu: TMainFormMenu;
     FMenu: TMainFormMenu;
     FLazPaintInstance: TLazPaintCustomInstance;
     FLazPaintInstance: TLazPaintCustomInstance;
-    FOnPictureAreaChange: TOnPictureAreaChange;
     FToolBoxDocking: TToolWindowDocking;
     FToolBoxDocking: TToolWindowDocking;
     FInSetToolBoxDocking: boolean;
     FInSetToolBoxDocking: boolean;
     FPanelToolBox: TPanel;
     FPanelToolBox: TPanel;
@@ -36,11 +41,23 @@ type
     FDarkTheme: boolean;
     FDarkTheme: boolean;
     FDockedControlsPanel: TPanel;
     FDockedControlsPanel: TPanel;
     FDockedChooseColorSplitter: TSplitter;
     FDockedChooseColorSplitter: TSplitter;
+    FPaintBox: TPaintBox;
+    FImageView: TImageView;
+    function GetFillSelectionHighlight: boolean;
+    function GetMouseButtonState: TShiftState;
     function GetPaletteVisible: boolean;
     function GetPaletteVisible: boolean;
     function GetPopupToolbox: TPopupMenu;
     function GetPopupToolbox: TPopupMenu;
     function GetStatusBarVisible: boolean;
     function GetStatusBarVisible: boolean;
     function GetStatusText: string;
     function GetStatusText: string;
     function GetToolBoxVisible: boolean;
     function GetToolBoxVisible: boolean;
+    function GetUpdatingPopup: boolean;
+    procedure ImageToolbarUpdate(Sender: TObject);
+    procedure ImageViewMouseBefore(ASender: TObject; AShift: TShiftState);
+    procedure ImageViewMouseMove(Sender: TObject; APosition: TPointF);
+    procedure ImageViewOnPaint(Sender: TObject);
+    procedure SetFillSelectionHighlight(AValue: boolean);
+    procedure SetOnPaintPicture(AValue: TNotifyEvent);
+    procedure SetUpdatingPopup(AValue: boolean);
     procedure StatusBar_Paint(Sender: TObject);
     procedure StatusBar_Paint(Sender: TObject);
     procedure ToolboxGroupMainButton_MouseMove(Sender: TObject; {%H-}Shift: TShiftState; {%H-}X,
     procedure ToolboxGroupMainButton_MouseMove(Sender: TObject; {%H-}Shift: TShiftState; {%H-}X,
       {%H-}Y: Integer);
       {%H-}Y: Integer);
@@ -58,8 +75,9 @@ type
     procedure ToolboxGroupToolbarButton_MouseEnter(Sender: TObject);
     procedure ToolboxGroupToolbarButton_MouseEnter(Sender: TObject);
     procedure ToolboxGroupToolbarButton_MouseLeave(Sender: TObject);
     procedure ToolboxGroupToolbarButton_MouseLeave(Sender: TObject);
     procedure ToolboxSimpleButton_Click(Sender: TObject);
     procedure ToolboxSimpleButton_Click(Sender: TObject);
+    procedure PaletteVisibilityChangedByUser(Sender: TObject);
+    procedure ZoomChanged(sender: TZoom; ANewZoom: single);
   protected
   protected
-    FLastWorkArea: TRect;
     FDockedToolboxGroup: array of record
     FDockedToolboxGroup: array of record
         Button: TToolButton;
         Button: TToolButton;
         Panel: TPanel;
         Panel: TPanel;
@@ -68,7 +86,6 @@ type
       end;
       end;
     function GetWorkArea: TRect; override;
     function GetWorkArea: TRect; override;
     function GetWorkAreaAt(AStage: TLayoutStage): TRect;
     function GetWorkAreaAt(AStage: TLayoutStage): TRect;
-    procedure RaisePictureAreaChange;
     procedure DoArrange;
     procedure DoArrange;
     procedure ApplyTheme;
     procedure ApplyTheme;
     function DockedControlsPanelWidth: integer;
     function DockedControlsPanelWidth: integer;
@@ -77,9 +94,14 @@ type
     procedure HideToolboxGroup(AGroupIndex: integer);
     procedure HideToolboxGroup(AGroupIndex: integer);
     procedure HideToolboxGroups;
     procedure HideToolboxGroups;
   public
   public
-    constructor Create(AForm: TForm);
+    DelayedPaintPicture: boolean;
+    constructor Create(AForm: TForm; AZoom: TZoom);
     destructor Destroy; override;
     destructor Destroy; override;
+    function CatchToolKeyDown(var AKey: Word): boolean;
+    function CatchToolKeyPress(var AKey: TUTF8Char): boolean;
+    function CatchToolKeyUp(var AKey: Word): boolean;
     procedure Arrange;
     procedure Arrange;
+    procedure CheckDelayedUpdate;
     procedure DockedToolBoxAddButton(AAction: TBasicAction);
     procedure DockedToolBoxAddButton(AAction: TBasicAction);
     procedure DockedToolBoxAddGroup(AActions: array of TBasicAction);
     procedure DockedToolBoxAddGroup(AActions: array of TBasicAction);
     procedure DockedToolBoxSetImages(AImages: TImageList);
     procedure DockedToolBoxSetImages(AImages: TImageList);
@@ -87,10 +109,12 @@ type
     procedure RemoveColorFromPalette(AColor : TBGRAPixel);
     procedure RemoveColorFromPalette(AColor : TBGRAPixel);
     procedure AddDockedControl(AControl: TControl);
     procedure AddDockedControl(AControl: TControl);
     procedure RemoveDockedControl(AControl: TControl);
     procedure RemoveDockedControl(AControl: TControl);
+    procedure PaintPictureNow;
+    procedure InvalidatePicture(AInvalidateAll: boolean);
+    procedure ShowNoPicture;
     property Menu: TMainFormMenu read FMenu write FMenu;
     property Menu: TMainFormMenu read FMenu write FMenu;
     property ToolBoxDocking: TToolWindowDocking read FToolBoxDocking write SetToolBoxDocking;
     property ToolBoxDocking: TToolWindowDocking read FToolBoxDocking write SetToolBoxDocking;
     property ToolBoxVisible: boolean read GetToolBoxVisible write SetToolBoxVisible;
     property ToolBoxVisible: boolean read GetToolBoxVisible write SetToolBoxVisible;
-    property OnPictureAreaChange: TOnPictureAreaChange read FOnPictureAreaChange write FOnPictureAreaChange;
     property LazPaintInstance: TLazPaintCustomInstance read FLazPaintInstance write SetLazPaintInstance;
     property LazPaintInstance: TLazPaintCustomInstance read FLazPaintInstance write SetLazPaintInstance;
     property ToolboxPopup: TPopupMenu read GetPopupToolbox write SetPopupToolbox;
     property ToolboxPopup: TPopupMenu read GetPopupToolbox write SetPopupToolbox;
     property PaletteVisible: boolean read GetPaletteVisible write SetPaletteVisible;
     property PaletteVisible: boolean read GetPaletteVisible write SetPaletteVisible;
@@ -98,6 +122,13 @@ type
     property StatusText: string read GetStatusText write SetStatusText;
     property StatusText: string read GetStatusText write SetStatusText;
     property DefaultToolboxDocking: TToolWindowDocking read GetDefaultToolboxDocking;
     property DefaultToolboxDocking: TToolWindowDocking read GetDefaultToolboxDocking;
     property DarkTheme: boolean read FDarkTheme write SetDarkTheme;
     property DarkTheme: boolean read FDarkTheme write SetDarkTheme;
+    property OnPaintPicture: TNotifyEvent read FOnPaintPicture write SetOnPaintPicture;
+    property OnToolbarUpdate: TNotifyEvent read FOnToolbarUpdate write FOnToolbarUpdate;
+    property OnPictureMouseMove: TPictureMouseMoveEvent read FOnPictureMouseMove write FOnPictureMouseMove;
+    property OnPictureMouseBefore: TPictureMouseBeforeEvent read FOnPictureMouseBefore write FOnPictureMouseBefore;
+    property FillSelectionHighlight: boolean read GetFillSelectionHighlight write SetFillSelectionHighlight;
+    property UpdatingPopup: boolean read GetUpdatingPopup write SetUpdatingPopup;
+    property MouseButtonState: TShiftState read GetMouseButtonState;
   end;
   end;
 
 
 function ToolWindowDockingToStr(AValue: TToolWindowDocking): string;
 function ToolWindowDockingToStr(AValue: TToolWindowDocking): string;
@@ -141,9 +172,11 @@ end;
 
 
 { TMainFormLayout }
 { TMainFormLayout }
 
 
-constructor TMainFormLayout.Create(AForm: TForm);
+constructor TMainFormLayout.Create(AForm: TForm; AZoom: TZoom);
 begin
 begin
   FForm := AForm;
   FForm := AForm;
+  FZoom := AZoom;
+  FZoom.OnZoomChanged:=@ZoomChanged;
   FPanelToolBox := TPanel.Create(nil);
   FPanelToolBox := TPanel.Create(nil);
   FPanelToolBox.BevelInner := bvNone;
   FPanelToolBox.BevelInner := bvNone;
   FPanelToolBox.BevelOuter := bvNone;
   FPanelToolBox.BevelOuter := bvNone;
@@ -183,11 +216,17 @@ begin
   FStatusTextSplit := TStringList.Create;
   FStatusTextSplit := TStringList.Create;
   FForm.InsertControl(FStatusBar);
   FForm.InsertControl(FStatusBar);
 
 
+  FPaintBox := TPaintBox.Create(nil);
+  FForm.InsertControl(FPaintBox);
+  FImageView := nil;
+
   ApplyTheme;
   ApplyTheme;
 end;
 end;
 
 
 destructor TMainFormLayout.Destroy;
 destructor TMainFormLayout.Destroy;
 begin
 begin
+  FreeAndNil(FImageView);
+  FreeAndNil(FPaintBox);
   FreeAndNil(FDockedControlsPanel);
   FreeAndNil(FDockedControlsPanel);
   FreeAndNil(FStatusBar);
   FreeAndNil(FStatusBar);
   FreeAndNil(FStatusTextSplit);
   FreeAndNil(FStatusTextSplit);
@@ -197,6 +236,27 @@ begin
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
+function TMainFormLayout.CatchToolKeyDown(var AKey: Word): boolean;
+begin
+  if Assigned(FImageView) then
+    result := FImageView.CatchToolKeyDown(AKey)
+    else result := false;
+end;
+
+function TMainFormLayout.CatchToolKeyUp(var AKey: Word): boolean;
+begin
+  if Assigned(FImageView) then
+    result := FImageView.CatchToolKeyUp(AKey)
+    else result := false;
+end;
+
+function TMainFormLayout.CatchToolKeyPress(var AKey: TUTF8Char): boolean;
+begin
+  if Assigned(FImageView) then
+    result := FImageView.CatchToolKeyPress(AKey)
+    else result := false;
+end;
+
 procedure TMainFormLayout.SetToolBoxDocking(AValue: TToolWindowDocking);
 procedure TMainFormLayout.SetToolBoxDocking(AValue: TToolWindowDocking);
 begin
 begin
   if FInSetToolBoxDocking or (FToolBoxDocking=AValue) then Exit;
   if FInSetToolBoxDocking or (FToolBoxDocking=AValue) then Exit;
@@ -209,7 +269,6 @@ begin
       FLazPaintInstance.Config.SetDefaultToolboxDocking(ToolWindowDockingToStr(AValue));
       FLazPaintInstance.Config.SetDefaultToolboxDocking(ToolWindowDockingToStr(AValue));
   end;
   end;
   DoArrange;
   DoArrange;
-  RaisePictureAreaChange;
   FInSetToolBoxDocking := false;
   FInSetToolBoxDocking := false;
 end;
 end;
 
 
@@ -218,6 +277,56 @@ begin
   result := LazPaintInstance.ToolboxVisible;
   result := LazPaintInstance.ToolboxVisible;
 end;
 end;
 
 
+function TMainFormLayout.GetUpdatingPopup: boolean;
+begin
+  if Assigned(FImageView) then
+    result := FImageView.UpdatingPopup
+    else result := False;
+end;
+
+procedure TMainFormLayout.ImageToolbarUpdate(Sender: TObject);
+begin
+  if Assigned(FOnToolbarUpdate) then
+    FOnToolbarUpdate(self);
+end;
+
+procedure TMainFormLayout.ImageViewMouseBefore(ASender: TObject;
+  AShift: TShiftState);
+begin
+  if Assigned(FOnPictureMouseBefore) then
+    FOnPictureMouseBefore(self, AShift);
+end;
+
+procedure TMainFormLayout.ImageViewMouseMove(Sender: TObject; APosition: TPointF);
+begin
+  if Assigned(FOnPictureMouseMove) then
+    FOnPictureMouseMove(self, APosition);
+end;
+
+procedure TMainFormLayout.ImageViewOnPaint(Sender: TObject);
+begin
+  if Assigned(FOnPaintPicture) then
+    FOnPaintPicture(self);
+end;
+
+procedure TMainFormLayout.SetFillSelectionHighlight(AValue: boolean);
+begin
+  if Assigned(FImageView) then
+    FImageView.FillSelectionHighlight := AValue;
+end;
+
+procedure TMainFormLayout.SetOnPaintPicture(AValue: TNotifyEvent);
+begin
+  if FOnPaintPicture=AValue then Exit;
+  FOnPaintPicture:=AValue;
+end;
+
+procedure TMainFormLayout.SetUpdatingPopup(AValue: boolean);
+begin
+  if Assigned(FImageView) then
+    FImageView.UpdatingPopup := AValue;
+end;
+
 procedure TMainFormLayout.StatusBar_Paint(Sender: TObject);
 procedure TMainFormLayout.StatusBar_Paint(Sender: TObject);
 var
 var
   colWidth, spacing, i, x: Integer;
   colWidth, spacing, i, x: Integer;
@@ -287,6 +396,12 @@ begin
   FLazPaintInstance:=AValue;
   FLazPaintInstance:=AValue;
   FPaletteToolbar.LazPaintInstance:= AValue;
   FPaletteToolbar.LazPaintInstance:= AValue;
   FStatusBarVisible := LazPaintInstance.Config.GetStatusBarVisible;
   FStatusBarVisible := LazPaintInstance.Config.GetStatusBarVisible;
+  if Assigned(FImageView) then FreeAndNil(FImageView);
+  FImageView := TImageView.Create(FLazPaintInstance, FZoom, FPaintBox);
+  FImageView.OnPaint:=@ImageViewOnPaint;
+  FImageView.OnToolbarUpdate:=@ImageToolbarUpdate;
+  FImageView.OnMouseMove:=@ImageViewMouseMove;
+  FImageView.OnMouseBefore:=@ImageViewMouseBefore;
 end;
 end;
 
 
 procedure TMainFormLayout.SetPaletteVisible(AValue: boolean);
 procedure TMainFormLayout.SetPaletteVisible(AValue: boolean);
@@ -316,11 +431,36 @@ begin
   Arrange;
   Arrange;
 end;
 end;
 
 
+procedure TMainFormLayout.ZoomChanged(sender: TZoom; ANewZoom: single);
+begin
+  if Assigned(FImageView) then
+  begin
+    if not LazPaintInstance.Image.SelectionMaskEmpty then
+      FImageView.ShowSelection := false;
+    FImageView.OnZoomChanged(sender, ANewZoom);
+  end;
+  PaintPictureNow;
+end;
+
 function TMainFormLayout.GetPaletteVisible: boolean;
 function TMainFormLayout.GetPaletteVisible: boolean;
 begin
 begin
   result := FPaletteToolbar.Visible;
   result := FPaletteToolbar.Visible;
 end;
 end;
 
 
+function TMainFormLayout.GetFillSelectionHighlight: boolean;
+begin
+  if Assigned(FImageView) then
+    result := FillSelectionHighlight
+    else result := false;
+end;
+
+function TMainFormLayout.GetMouseButtonState: TShiftState;
+begin
+  if Assigned(FImageView) then
+    result := FImageView.MouseButtonState
+    else result := [];
+end;
+
 procedure TMainFormLayout.SetPopupToolbox(AValue: TPopupMenu);
 procedure TMainFormLayout.SetPopupToolbox(AValue: TPopupMenu);
 begin
 begin
   FPanelToolBox.PopupMenu := AValue;
   FPanelToolBox.PopupMenu := AValue;
@@ -440,12 +580,6 @@ begin
   if AStage = lsAfterStatusBar then exit;
   if AStage = lsAfterStatusBar then exit;
 end;
 end;
 
 
-procedure TMainFormLayout.RaisePictureAreaChange;
-begin
-  if Assigned(FOnPictureAreaChange) then
-    FOnPictureAreaChange(self, WorkArea);
-end;
-
 procedure TMainFormLayout.DoArrange;
 procedure TMainFormLayout.DoArrange;
 var nbY,nbX,w,i: integer;
 var nbY,nbX,w,i: integer;
   updateChooseColorHeight: Boolean;
   updateChooseColorHeight: Boolean;
@@ -522,6 +656,9 @@ begin
     end;
     end;
   end
   end
   else FStatusBar.Visible := false;
   else FStatusBar.Visible := false;
+  if Assigned(FImageView) then
+    with WorkArea do
+    FImageView.SetBounds(Left, Top, Width, Height);
 end;
 end;
 
 
 procedure TMainFormLayout.ApplyTheme;
 procedure TMainFormLayout.ApplyTheme;
@@ -622,28 +759,36 @@ begin
 end;
 end;
 
 
 procedure TMainFormLayout.Arrange;
 procedure TMainFormLayout.Arrange;
-var picAreaBeforeArrange,newPicArea: TRect;
 begin
 begin
-  picAreaBeforeArrange := WorkArea;
   DoArrange;
   DoArrange;
   HideToolboxGroups;
   HideToolboxGroups;
-  newPicArea := WorkArea;
-  if (newPicArea.Left <> picAreaBeforeArrange.Left) or
-     (newPicArea.Top <> picAreaBeforeArrange.Top) or
-     (newPicArea.Right <> picAreaBeforeArrange.Right) or
-     (newPicArea.Bottom <> picAreaBeforeArrange.Bottom) or
-     (newPicArea.Left <> FLastWorkArea.Left) or
-     (newPicArea.Top <> FLastWorkArea.Top) or
-     (newPicArea.Right <> FLastWorkArea.Right) or
-     (newPicArea.Bottom <> FLastWorkArea.Bottom) then
-  begin
-    RaisePictureAreaChange;
-    FLastWorkArea := newPicArea;
-  end;
   if Assigned(FMenu) then
   if Assigned(FMenu) then
     FMenu.RepaintToolbar;
     FMenu.RepaintToolbar;
 end;
 end;
 
 
+procedure TMainFormLayout.CheckDelayedUpdate;
+begin
+  if (LazPaintInstance = nil) or (FImageView = nil) then exit;
+
+  if FImageView.CanCompressOrUpdateStack and LazPaintInstance.UpdateStackOnTimer then
+  begin
+    LazPaintInstance.NotifyStackChange;
+    LazPaintInstance.UpdateStackOnTimer := false;
+  end else
+  begin
+    if FImageView.CanCompressOrUpdateStack then LazPaintInstance.Image.CompressUndo;
+  end;
+
+  if DelayedPaintPicture or LazPaintInstance.ToolManager.ToolUpdateNeeded or
+   (not FImageView.ShowSelection and
+    (Now > FImageView.LastPaintDate+SelectionPaintDelay) ) then
+  begin
+    if LazPaintInstance.ToolManager.ToolUpdateNeeded then LazPaintInstance.ToolManager.ToolUpdate;
+    if Assigned(FImageView) then FImageView.ShowSelection := true;
+    PaintPictureNow;
+  end;
+end;
+
 procedure TMainFormLayout.DockedToolBoxAddButton(AAction: TBasicAction);
 procedure TMainFormLayout.DockedToolBoxAddButton(AAction: TBasicAction);
 var button: TToolButton;
 var button: TToolButton;
 begin
 begin
@@ -775,5 +920,23 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TMainFormLayout.PaintPictureNow;
+begin
+  if Assigned(FImageView) then
+    FImageView.UpdatePicture;
+end;
+
+procedure TMainFormLayout.InvalidatePicture(AInvalidateAll: boolean);
+begin
+  if Assigned(FImageView) then
+    FImageView.InvalidatePicture(AInvalidateAll);
+end;
+
+procedure TMainFormLayout.ShowNoPicture;
+begin
+  if Assigned(FImageView) then
+    FImageView.ShowNoPicture;
+end;
+
 end.
 end.