Jump to content

Anders Melander

Members
  • Content Count

    2771
  • Joined

  • Last visited

  • Days Won

    147

Everything posted by Anders Melander

  1. Anders Melander

    compiling DCU without creating EXE

    Congratulations. -J* makes the compiler output .obj files instead of dcu files. -JHurrah!NoDCUs works "just as well". -h will tell you all the command line switches. No need to have an AI invent new ones.
  2. Btw, you might want to check out the Image32Background and PanAndZoom examples in the image32_background branch. They demonstrate how to do the following without any custom code (they are now built-in optional features in TImage32/TImgView32): and panning & animated (using cubic tweening) exponential zoom with pivot point:
  3. I would just store a reference to your object and the object owner in the layer and then notify the owner when the layer is moved. Something like this: type TObjectLayer = class; TObjectLayerNotification = ( olnDestroy, // Subscribers should remove reference to layer olnPosition // Layer has moved ); IObjectLayerNotification = interface ['{C5715B62-6D20-4BEE-841A-A898AA67D6F7}'] procedure ObjectLayerNotification(ALayer: TObjectLayer; ANotification: TObjectLayerNotification); end; TObjectLayer = class(TIndirectBitmapLayer) private FSubscribers: TList<IObjectLayerNotification>; FObjectID: TSomeType; protected procedure Notify(ANotification: IObjectLayerNotification); procedure DoSetLocation(const NewLocation: TFloatRect); override; public destructor Destroy; override; procedure Subscribe(const ASubscriber: IObjectLayerNotification); procedure Unsubscribe(const ASubscriber: IObjectLayerNotification); property ObjectID: TSomeType read FObjectID write FObjectID; end; destructor TObjectLayer.Destroy; begin Notify(olnDestroy); FSubscribers.Free; inherited; end; procedure TObjectLayer.DoSetLocation(const NewLocation: TFloatRect); begin inherited DoSetLocation(NewLocation); Notify(olnPosition); end; procedure TObjectLayer.Notify(ANotification: IObjectLayerNotification); begin if (FSubscribers = nil) then exit; for var Subscriber in FSubscribers.ToArray do // ToArray for stability Subscriber.ObjectLayerNotification(Self, ANotification); end; procedure TObjectLayer.Subscribe(const ASubscriber: IObjectLayerNotification); begin if (FSubscribers = nil) then FSubscribers := TList<IObjectLayerNotification>.Create; FSubscribers.Add(ASubscriber); end; procedure TObjectLayer.Unsubscribe(const ASubscriber: IObjectLayerNotification); begin if (FSubscribers <> nil) then FSubscribers.Remove(ASubscriber); end; The object ID is stored in the ObjectID property (change the type to whatever type you use an an ID). The owner must implement the IObjectLayerNotification interface and call Subscribe on the layer to get notifications. This is a pretty standard observer pattern. If you are using the TRubberbandLayer then there's a OnConstrain event where you can examine and modify the move/resize. If you are doing move/resize with some other method then I'll need some information about that. I usually implement rubber-band selection via the TImgView32 mouse events (i.e. I'm not using a layer). So I manage the selection-in-progress state (usually just the mouse-down position) and any current selection on the form. In the mouse-up handler, I create a rectangle polygon from the mouse-down pos and the mouse-up pos and then either replace the current selection with the new one or merge the two (union), depending on the keyboard shift state. The selection is stored as a polygon. You can also use a polypolygon depending on your needs. The selection is drawn by a custom layer (visible only when there actually is a selection). The layer has a copy of the polygon and draws a marching ants (btw, try googling "marching ants") animated line using a stipple pattern and a timer. Here's the Paint method of the layer: procedure TSelectionLayer.Paint(Buffer: TBitmap32); begin try // Update local copy of selection polygon UpdateCache; if (BitmapEditor.HasSelection) then begin Buffer.SetStipple(SelectionStipple); Buffer.StippleCounter := FSelectionStippleCounter; Buffer.StippleStep := 1; PolylineXSP(Buffer, FCachedSelection, not SelectionInProgress); end; except // Prevent AV flood due to repaint Visible := False; raise; end; end; and the setup and control of the stipple pattern: constructor TSelectionLayer.Create(ABitmapEditor: TBitmapEditor); begin inherited Create(ABitmapEditor); FCacheValid := False; FTimer := TTimer.Create(nil); FTimer.Interval := 50; FTimer.OnTimer := OnTimer; FTimer.Enabled := False; CreateStipple(FSelectionStipple, $F0F0F0F0, clBlack32, clWhite32); end; procedure TSelectionLayer.OnTimer(Sender: TObject); begin // TODO : Remove dependency on Forms unit if (not Application.Active) then exit; FSelectionStippleCounter := FSelectionStippleCounter+1.5; if (FSelectionStippleCounter >= Length(SelectionStipple)) then FSelectionStippleCounter := FSelectionStippleCounter - Length(SelectionStipple); Update(FBitmapRect); end;
  4. Anders Melander

    bitmap is not displayed

    Don't expect people to help you if you don't want to make an effort yourself. You need to make it as easy as possible for us to help you. Generally, when describing a problem there are 4 things you need to state: What are you trying to do (high-level description)? E.g. I'm trying to display a bitmap How are you doing it (the steps)? Clean up your code. Post the whole method/function and use the code tag (the </> button). What is the expected result? E.g. The bitmap is drawn in the window What is the actual/observed result? E.g. Nothing is drawn in the window You don't need to write it as a list but unless we have all this information we will have to guess and that just slows things down. See also: https://stackoverflow.com/help/how-to-ask
  5. The code was copied from TCustomBitmapLayer in GR32_Layers, so you can find it there: type TImage32Access = class(TCustomImage32); Stretchtransfer is declared in GR32_Resamplers. I'm considering making TIndirectBitmapLayer the base class for TCustomBitmapLayer.
  6. As I've explained to you before, the reason why there are so many variants is that a line is a low-level primitive and the many different variants cover 3 different coordinate types (fixed, float, integer) and different combinations of orientation, anti-aliasing, transparency, stippling, and clipping options. Each one optimized for its particular feature subset. Sure, we could have just replaced them all with a single mediocre all-in-one method, but then why use Graphics32 at all if not for the performance gains possible with specialization? If the library architecture is poorly designed, or the architecture has become obsolete, then I would agree that it might make sense to start from scratch. I don't really think that's what we're talking about here, though. It's just so much easier (and often more fun) to write code when you don't have to stay within the constraints of an existing framework. I think many libraries, not just graphics libraries, start as someone's hobby experiment and eventually end up growing into a fully featured library that does the same as all the others, but in a slightly different way. From an evolutionary POV diversity is good, but with an eco-system as small as Delphi's I think it just fragments the users - and the contributors. Yes, that's definitely a problem. https://github.com/graphics32/graphics32/issues/69 Wow. I can't speak about how things are in Australia, but at the companies I work with there are more "young" Delphi developers than "old" ones (and I'm not defining "young" as "younger than me" 🙂 ). WRT Anders Hejlsberg isn't it time to let that one go? He was just a (very skilled) developer who left for another job. It happens, you know.
  7. No, I don't think it should. A layer is a fairly small object so the overhead should be negligible. I think the easiest way to do it with layers would be to have each layer associated with a bitmap (i.e. it contains a reference to the bitmap, not a copy of the bitmap) and then have the layer draw the bitmap onto the TImage32 back-buffer. One has scrollbars (to move the viewport), and the other doesn't. That's about it I think. No, definitely not. Each layer draws itself onto the back buffer on demand (i.e. when the TImage32 requests it). To force a layer to redraw itself you call the layer Changed method. To force a full redraw call TImage32.Changed You can either use a standard TPositionedLayer (and draw in its OnPaint event handler) or a simple custom layer class that can draw itself: type TIndirectBitmapLayer = class abstract(TPositionedLayer) // Based on TCustomBitmapLayer. Does not own the bitmap it draws. private FBitmap: TBitmap32; FCropped: Boolean; protected procedure Paint(Buffer: TBitmap32); override; protected procedure SetCropped(Value: Boolean); property Bitmap: TBitmap32 read FBitmap; public constructor Create(ALayerCollection: TLayerCollection; ABitmap: TBitmap32); property Cropped: Boolean read FCropped write SetCropped; end; constructor TIndirectBitmapLayer.Create(ALayerCollection: TLayerCollection; ABitmap: TBitmap32); begin inherited Create(ALayerCollection); FBitmap := ABitmap; end; procedure TIndirectBitmapLayer.Paint(Buffer: TBitmap32); var SrcRect, DstRect, ClipRect, TempRect: TRect; ImageRect: TRect; begin if FBitmap.Empty then Exit; DstRect := MakeRect(GetAdjustedRect(Location)); ClipRect := Buffer.ClipRect; GR32.IntersectRect(TempRect, ClipRect, DstRect); if GR32.IsRectEmpty(TempRect) then Exit; SrcRect := MakeRect(0, 0, FBitmap.Width, FBitmap.Height); if Cropped and (LayerCollection.Owner is TCustomImage32) and (not TImage32Access(LayerCollection.Owner).PaintToMode) then begin if (DstRect.Width < 0.5) or (DstRect.Height < 0.5) then Exit; ImageRect := TCustomImage32(LayerCollection.Owner).GetBitmapRect; GR32.IntersectRect(ClipRect, ClipRect, ImageRect); end; StretchTransfer(Buffer, DstRect, ClipRect, FBitmap, SrcRect, FBitmap.Resampler, FBitmap.DrawMode, FBitmap.OnPixelCombine); end; procedure TIndirectBitmapLayer.SetCropped(Value: Boolean); begin if Value <> FCropped then begin FCropped := Value; Changed; end; end; A standard TRubberbandLayer can be associated with a single "child layer" at a time and can then be used to move and resize that child layer. You will probably want something that can handle multi-selection. I would look at how TRubberbandLayer works and try to extend that. Drawing of object frames and similar stuff can be done in layers that sit below or on top of everything else. For example look at the following (it's from a bitmap editor): From bottom to top we have: Background, including frame with drop-shadow Checkerboard pattern Image layers (there's two in this example) Raster grid Selection mask (marching ants) Tool cursor (a stippled polygon) //------------------------------------------------------------------------------ // // TBitmapEditor Layers and Paint Stages // //------------------------------------------------------------------------------ (* +---------------------+ ^ / / | / Hotspot /-+ | +---------------------+ / | / Cursor /-+ | +---------------------+ / | / Selection /-+ | +---------------------+ / | / Mask /-+ Layers ---> | +---------------------+ / | / Grid /-+ | +---------------------+ / | / Tool rendering /-----+ | +---------------------+ / | / Layer 2 /-+ | +---------------------+ / | / Layer 1 /-+ | +---------------------+ / | / Floating selection /-+ | +---------------------+ / | / Layer 0 /-----+ ^ +---------------------+ / | / Image /-+ | +---------------------+ / | <--- Stages / Background /-+ | +---------------------+ / | / / +---------------------+ *) I think you should start by getting the bitmap layers working and then we can talk about how to handle the selection UI later.
  8. Actually, now that I think of it, a TRubberBandLayer is used to move and resize another layer (see the ImgView_Layers example). For freehand rubber band selection, you would need to implement a custom layer. It's pretty simple. Btw, have you seen this old post:
  9. I haven't seen you ask for help anywhere. You could have tried that. I can probably tell you how to solve your problems with Graphics32, should you choose to continue that way, but you need to ask the questions first 🙂 I believe Image32 does layers too and it might be more accessible than Graphics32. When @angusj comes online he can chime in on that. If you're using the TImage32 or TImgView32 controls then the double buffering is already built in and handled automatically. Each layer just needs to draw itself into a bitmap and the control will take care of the rest. Use a TRubberbandLayer. The layer is drawn on demand onto a bitmap like all other layers but that is already done by TRubberbandLayer so you don't need to do anything special. It depends on your needs. One possible solution is to have each vector object be represented by its own layer. Another is to draw all objects onto a single layer. Or you could do a combination. For simplicity, I would probably choose to draw all objects onto a single layer. Regardless TImage32 takes care of producing the final combined image.
  10. The kiss of death. Apart from I don't see it happening. What would "the VCL" use it for?
  11. Anders Melander

    bitmap is not displayed

    Ok then, imassumingthatthisisaWM_PAINThandler.ifnot,thenyouneedtoreadtheBeginPaintdocumentation.ifitis,thenthere'samissingcalltoEndPaint.youarealsonotusingtheinformationinPAINTSTRUCTfilledoutbyBeginPaint. andfinally,youstillhaven'ttolduswhattheactualproblemis.
  12. Anders Melander

    bitmap is not displayed

    Is it too much to ask that you make your code readable if you're asking other people to spend their time reading it? There's a whole bunch of stuff missing from the code you posted. So much that there's not much point in trying to figure out what problem you're having (you might also have stated that. we're not mind readers).
  13. That's great! However, as far as I can tell, there's no documentation to explain this behavior. A bit unfortunate, to say the least. Or maybe I'm just not understanding how association arrays work. I have already updated my code to support registration under HKCU\Software\Classes instead of HKCR. I will update it to also add the SystemFileAssociation keys.
  14. ShellExView seems to be having problems reading the registry entries related to my Property Sheet Handler (this is on both Windows 7 & 10):
  15. I've now compared the log from Windows 7 and Windows 10.somethingsomething. I searched for "arw" in both logs. What stands out is that on Windows 7 the Explorer primarily uses the registry keys we're expecting; The documented ones. For example, it looks for (and finds) the property sheet handler in HKCU\Software\Classes\arwfile\shellex\PropertySheetHandlers and HKCR\arwfile\shellex\PropertySheetHandlers. On Windows 10 however, things are a bit different. Notably, it never looks for *arwfile\shellex\* Both Windows 7 and Windows 10 look for (and don't find) HKCU\Software\Classes\SystemFileAssociations\.arw\shellex\PropertySheetHandlers and HKCR\SystemFileAssociations\.arw\shellex\PropertySheetHandlers. They also read the more general keys HKCU\Software\Classes\*\shellex\PropertySheetHandlers, and HKCR\*\shellex\PropertySheetHandlers and Windows 10 additionally looks for HKCU\Software\Classes\Kind.Picture\shellex\PropertySheetHandlers and HKCR\Kind.Picture\shellex\PropertySheetHandlers. Apparently, the SystemFileAssociations keys are related to something called Association Arrays.
  16. It's about 40,000 log entries on both systems, so it's not a small task. It's worth a try though. One might get lucky.
  17. I just tried (on Windows 10) to: Remove/rename all the non property sheet related registry key/values from the .arw and arwfile registry keys. Copy all the .arw and arwfile registry key/values from HKLM to HKCU. None of this made any difference. I then renamed the HKCU .arw to .xxx and arwfile to xxxfile and was then able to display the property page on a test.xxx file. So my experience now matches yours 😞
  18. I have another application registered to open it by default (PhotoStage), but yes, double-clicking your file in Explorer opens it correctly. Selecting "Properties" in Explorer bombed on the real file. The reason might be that there's another shell extension registered on the file type and that it's this extension that is causing the crash. All this is on Windows 7. On Windows 10 and later the property page is not displayed (and the arw-file is opened in Photo Viewer).
  19. Doesn't work for me either on Windows 10 and later...
  20. Yes, but the property page crashes explorer (endless "invalid window handle" error messages) with an actual .arw file. An empty text file renamed to xxx.arw works fine. I believe this is a problem with the content functionality of the property page, not with the registration and display of the property page (i.e. it's not related to this thread). Sure. I also shouldn't smoke and eat bacon 🙂 I have Windows 11 on my laptop for when I need a reminder of why I still use Windows 7 on my desktop.
  21. Anders Melander

    FireDAC performances

    Where else would it execute it? Did you expect it to execute the query locally? If you execute the exact same query remotely via FireDAC and remotely via SQL Server Management Studio and they don't perform almost the same, then the problem is most likely the way the data is fetched by the client. I solved a similar performance problem at one time by fiddling with some connection parameters... Here are the screenshots I took to document the difference in performance: Query executed via MSSQL MS: Same query executed via TFDQuery: Try to compare the network bandwith usage of FireDAC vs SQL Server Management Studio when the query execute/fetches, like I did above. Again, they should be almost identical. In the above case, I solved the problem by disabling MARS on the connection. Query executed via TFDQuery on a connection with MARS disabled:
  22. Still works for me: I'm on a 64-bit Windows 7 so it might be the same problem as this: https://stackoverflow.com/questions/34011698/property-sheet-handlers-on-windows-10
  23. I already did. What do you mean?
  24. Anders Melander

    libs that do EFX for text?

    As I wrote: https://www.google.com/search?q=delphi+graphics+transitions As far as I can tell there's a ton of old transition effects code on Torry.net. No guarantee that it works as-is with newer versions of Delphi though.
×