Quantcast
Channel: Delphi Haven
Viewing all 62 articles
Browse latest View live

FMX menu unfurling speed

$
0
0

A bit ago I posted a QC report complaining about the speed at which a nested FMX popup menu unfurls. Steps:

  1. Create a new FMX desktop application.
  2. Add a TPopupMenu to the form, then four items to the popup menu, the second parented to the first, the third to second and the fourth to the third.
  3. Add a TRectangle to the form and assign its PopupMenu property to PopupMenu1.
  4. Right click on the popup menu, select the first item then hover over the second; once the third item is shown, hover over it to show the fourth.

Expected: the menu unfolds quickly.
Actual: the menu unfolds sloooowly.

At the time I thought FMX menus were just slow… until it recently got pointed out to me that the FMX source in fact hardcodes a delay of 500ms. As such, if you require quickly unfurling menus, just take a copy of FMX.Menus.pas and change the value assigned to FDelay in the constructor for TAutopopupMenuTimer (line 575 in XE5 RTM).

That said, ideally, the correct value would be got from the OS; for Windows, the API function to call is SystemParametersInfo:

uses
  WinApi.Windows;

function GetMenuShowDelay: Integer;
var
  Value: DWORD;
begin
  SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, @Value, 0);
  Result := Value;
end;

To be honest, I’m not sure what the OS X equivalent (if there is one) is, so if anyone knows, feel free to tell all in the comments…



XE5 update 1 is out

Working around an XE5/Mac menu issue

$
0
0

In XE5, if you try running the FMX ‘ActionsDemo’ sample project on OS X, you’ll quickly find an issue – the menu bar isn’t set up correctly:

ActionsDemo menu wrong
ActionsDemo menu wrong 2

ActionsDemo menu wrong 3
If you open up the menu designer in the IDE, you’ll find what should be happening is that the application menu gets four items: Hide ActionsDemo, Hide Others, a separator, and Quit ActionsDemo, with all but the separator having an appropriate shortcut assigned:

ActionsDemo menu designer
Each of the three substantive items uses a standard FMX action, and to be honest, I have always found them poorly coded since they were introduced in XE3. However, the menu bar not being built correctly at all didn’t happen in XE3.

Comparing the FMX Mac menu bar source code between XE3 and XE5 doesn’t come up with much though – the code for building the default menu bar has been split out into its own method, and that’s about it. However, after adding a couple of breakpoints and running the ActionsDemo sample through the debugger, I discovered the key method – TPlatformCocoa.CreateOSMenu – being called several times when the application was starting up. Partly this was due to style notifications, and partly due to the code being re-entrant in a somewhat sloppy way – TPlatformCocoa.CreateOSMenu first gets rid of what was there before, however the clean-up code for a FMX menu item on OS X religiously calls CreateOSMenu to rebuild the menubar regardless of whether the item is being destroyed singularly, or as part of a general ‘get rid of everything’ call. Since the CreateOSMenu code in itself doesn’t take account of possible re-entrancy (i.e., being called again when it hasn’t yet finished the time before)… the end result is not well determined.

As such, a quick fix for the re-entracy issue is to add a flag to avoid CreateOSMenu doing its stuff when it hasn’t finished doing it before:

  • Take a copy of FMX.Platform.Mac.pas
  • In the copy, add the following private field to TPlatformCocoa:
FCreatingOSMenu: Boolean;
  • Amend the top of TPlatformCocoa.CreateOSMenu to look like this:
if FCreatingOSMenu then Exit; //!!!added
AutoReleasePool := TNSAutoreleasePool.Create;
try
  FCreatingOSMenu := True;    //!!added
  • Amend the bottom of TPlatformCocoa.CreateOSMenu to look like this:
finally
  FCreatingOSMenu := False;    //!!!added
  AutoReleasePool.release;
end;
  • Save the unit, add it to the project, and rebuild.

While this fix gets rid of the MacOSMenuItem top level item that shouldn’t be there, things still aren’t OK though:

ActionsDemo menu still wrong

Notice the application menu is still missing Hide ActionsDemo and Hide Others. This is because the action classes used – TFileHideApp and TFileHideAppOthers – are poorly coded. Happily, they can be avoided easily enough though, and without requiring platform specific code as such:

  • Add the following private field to the form:
FHideAppService: IFMXHideAppService;
  • In the form’s OnCreate event handler, retrieve the platform service in the normal way:
FHideAppService := TPlatformServices.Current.GetPlatformService(
  IFMXHideAppService) as IFMXHideAppService;
  • Bring up the form’s designer surface, right click on it and select View as Text.
  • Find TFileHideApp and TFileHideAppOthers at the end, and change the types to plain TAction.
  • Right click and choose View as Form.
  • Double click the action list, and in the action list editor, find and put back the two actions’ standard Text and ShortCut properties – the Text for FileHideApp1 should be ‘Hide ActionsDemo’ and the ShortCut Cmd+H; the Text for FileHideAppOthers1 should be ‘Hide Others’ and the ShortCut Cmd+Alt+H.
  • Handle FileHideAppOthers1′s OnExecute event like this:
procedure TMainForm.FileHideAppOthers1Execute(Sender: TObject);
begin
  FHideAppService.HideOthers;
end;
  • Handle FileHideApp1′s OnUpdate event like this (in practice the code isn’t necessary for how the demo is set up – SDI not Mac-style MDI – but we’ll add it for completeness):
procedure TMainForm.FileHideApp1Update(Sender: TObject);
begin
  (Sender as TCustomAction).Enabled := not FHideAppService.Hidden;
end;
  • Handle FileHideApp1′s OnExecute event like this:
procedure TMainForm.FileHideApp1Update(Sender: TObject);
begin
  FHideAppService.Hidden := True;
end;
  • On saving (Ctrl+S), you’ll be prompted to update two type declarations; answer Yes to both. Re-run the demo, and the menu bar should now be set up correctly:

ActionsDemo menu fixed

-

PS (and changing the subject) – for those who contacted me a bit ago about my Exif code, sorry, I will get round to replying, but I’ve just been busy with other things recently.


Native Android controls for XE5

If you write database applications in Delphi…

$
0
0

… you may want to contribute to the following thread on the Embarcadero forums:

https://forums.embarcadero.com/thread.jspa?messageID=620961&tstart=0#620961

Quote:

Hello All

At moment the DB RTL team is working on Data.DB.pas improvements. This is a good moment to bring our attention to the DB related issues registered in QC, which are important / valuable / annoying from your point of view. Please post your replies to this message with QC numbers and optional comments describing the importance of the issues. Thank you.


With best regards,
Dmitry Arefiev / FireDAC Architect


InfoPower grid for FireMonkey – free with XE5

$
0
0

In case anyone interested in FMX isn’t aware, Woll2Woll’s InfoPower grid for FireMonkey can be got free with XE5. OK, no source, but it’s much, much better than the standard offering:

InfoPower

If you want to see the Android targeting in action, Woll2Woll have a demo on Google Play (https://play.google.com/store/apps/details?id=com.woll2woll.IP2SearchGridDemo&hl=en).

That said, one small issue I’ve found is that the setup file available on ‘My Registered Downloads’ at Embarcadero’s site is a bit outdated – on opening one of the iOS demos and building, I got a compiler error:

[DCC Fatal Error] SearchGrid.pas(10): F2051 Unit fmx.wwlayouts was compiled with a different version of FMX.Effects.TEffect

Presumably this is due to update 2 breaking DCU compatibility for iOS targets (this issue is mentioned in the update 2 readme files). To fix, I downloaded the latest setup file from Woll2Woll’s website and installed over the top of the original installation – see the top link here:

http://www.woll2woll.com/download-infopower-release-versions.html

Having done that, the iOS demos now compiled fine.


Removing a FMX control’s size restrictions

$
0
0

One rather annoying aspect of FMX’s evolution has been a restriction on control sizes. The most notorious case is probably TGroupBox, which in XE4′s iOS support was bizarrely matched to Safari’s toolbar (i.e., a standard control with a non-standard height), rendering the thing useless. Nevertheless, the general rationale for fixed sizing is not ridiculous – different platforms have different standard sizes for buttons, toolbars and so forth, so it makes sense for FMX to assist the developer in ensuring these conventions are respected. Even so, the implementation taken has been distinctly sub-optimal in my view – in particular, I would have much preferred an AutoSize property that defaults to True. As things stand, standard sizes are instead hardcoded in internal style code and trump even the Align property.

For example, here’s a right-aligned TSpeedButton with its StyleLookup set to ‘composetoolbutton’ and parented to a TListBoxItem, running on an Android tablet. I’ve taken the screenshot as I am pressing the button down – notice how this clearly shows it to be taller than its parent:

Too tall TSpeedButton

Happily, this dubious behaviour can be prevented by overriding the control’s AdjustFixedSize method however. To implement this fix in the form of an interposer class, declare the following immediately before the form type:

type
  TSpeedButton = class(FMX.StdCtrls.TSpeedButton)
  protected
    procedure AdjustFixedSize(const Ref: TControl); override;
  end;

Next, implement the method like so:

procedure TSpeedButton.AdjustFixedSize(const Ref: TControl);
begin
  SetAdjustType(TAdjustType.None);
end;

Fix added, a speed button’s Align property will now be properly respected:

Fixed TSpeedButton


Inspecting ‘platform’ styles redux

$
0
0

Back when XE3 was current I blogged about retrieving the default FMX styles for Windows and OS X, a process less transparent than in XE2 when the standard styles were distributed as *.style files. Roll onto mobile support in XE4 and XE5, and the default styles are if anything even more hidden. Nevertheless, it is possible to recover them and get human-readable *.style files:

1. Find the resource name; for Android this is currently ‘androidstyle’ (see FMX.Controls.Android.pas), for iOS one of ‘iphonestyle’, ‘ipadstyle’ or ‘iphonepadstyle_Modern’ (= iOS 7; see FMX.Controls.iOS.pas).

2. Create a blank new mobile project, and in the form’s OnCreate event, load and output the desired resource to a file. For example, for Android you might do this:

uses System.IOUtils;

procedure TForm1.FormCreate(Sender: TObject);
var
  FN: string;
  Stream: TResourceStream;
begin
  FN := TPath.Combine(TPath.GetHomePath, 'FMX default.style');
  Stream := TResourceStream.Create(HInstance, 'androidstyle', RT_RCDATA);
  Stream.SaveToFile(FN);
  ShowMessage('Saved to ' + FN);
end;

3. Run the app on a device.

4. Manually copy over the extracted file to your development PC or VM.

5. Back in your dummy project, add a TStyleBook component to the form, and double click it to open the style book editor.

6. Click the ‘Load’ button and locate the extracted *.style file.

7. Click the ‘Save’ button and overwrite the extracted *.style file.

The reason for step (7) is because the style will be extracted in a binary format, and resaving in the style book editor will output to a textual one. More specifically, it will convert from the DFM binary format to the DFM textual one with just a simple header added – FMX being based on the VCL’s streaming system as much as the VCL itself.

Removing platform restrictions

If between running the dummy app on the device and loading the extracted style file into the style book you changed the active target platform, the style book editor will complain:

Style load error

To prevent this happening in future, once you have reselected the ‘correct’ target platform (Android in my case) and now successfully loaded the style file, select the style’s ‘description’ component in the Structure pane and press Delete:

Delete style description

Having clicked Apply (or Apply and Close), the style will also now load when you select a different platform (just remember that to make a style book active, the form’s StyleBook property needs to be assigned). Here for example is the Android style used when running on Windows:

Android style on Windows

While XE5 update 2 introduced a special ‘mobile preview’ style for testing mobile projects on Windows, you can’t beat having the style that will actually be used on a device I think.



Improved XE5 mobile previews part 2

$
0
0

Last time around I blogged about how to extract the default XE5 mobile styles into *.style files – in a nutshell, you need to create an app that extracts the desired style resource to a file, then open the file in the stylebook editor, delete the ‘Description’ resource, and resave. In that post I went on to suggest using the extracted files in TStyleBook components. There is however a better way – provide a custom FMX.MobilePreview unit instead (NB: for all about the standard mobile previews – introduced in XE5 update 2 – check out either Marco Cantù’s blog post or the documentation).

To do this, create a new unit and, modeling on the standard FMX.MobilePreview.pas, add the following code:

unit FMX.MobilePreview;
{
  Use actual Android style
}
interface

implementation

{$IFDEF MSWINDOWS}

{$IF CompilerVersion <> 26}
  {$MESSAGE Error 'Custom FMX.MobilePreview.pas expects XE5!'}
{$IFEND}

uses
  System.Types, System.SysUtils, FMX.Styles, FMX.Graphics, FMX.Platform;

var
  OldInitProc: TProcedure;

procedure InitializeStyle;
begin
  if Assigned(OldInitProc) then
    OldInitProc();
  //!!!change path to whereever you have put the resaved *.style file
  TStyleManager.SetStyle(TStyleManager.LoadFromFile('C:\Delphi\LibXE5\Android.style'));
end;

initialization
  OldInitProc := InitProc;
  InitProc := @InitializeStyle;

finalization
  TStyleManager.SetStyle(nil);
  TCanvasManager.UnInitialize;
{$ENDIF}
end.

If you save the unit as FMX.MobilePreview.pas, compile and ensure the DCUs are in the global search path, you can have the IDE pick it up rather than the standard FMX.MobilePreview.pas. Alternatively, save it under a different name and just amend your project files to use it rather than FMX.MobilePreview.

That said, if you do this, something still won’t quite be right – namely, the font:

Font not right

This is because in the current FireMonkey code, the default font is a property of the platform rather than the style. As such, the font used here is a regular Windows one rather than Roboto, the default font on Android. Fixing this discrepancy is easy however – back in the custom unit, first add the following class immediately after the uses clause:

type
  TFMXSystemFontService = class(TInterfacedObject, IFMXSystemFontService)
  public
    function GetDefaultFontFamilyName: string;
  end;

function TFMXSystemFontService.GetDefaultFontFamilyName: string;
begin
  Result := 'Roboto';
end;

Secondly, unregister the standard IFMXSystemFontService implementation before registering our own by adding the following lines at the top of the unit’s initialization block:

  TPlatformServices.Current.RemovePlatformService(IFMXSystemFontService);
  TPlatformServices.Current.AddPlatformService(IFMXSystemFontService, TFMXSystemFontService.Create);

In all, the code for unit should now look like this:

unit FMX.MobilePreview;
{
  Use actual Android style
}
interface

implementation

{$IFDEF MSWINDOWS}
{$IF CompilerVersion <> 26}
  {$MESSAGE Error 'Custom FMX.MobilePreview.pas expects XE5!'}
{$IFEND}
uses
  System.Types, System.SysUtils, FMX.Styles, FMX.Graphics, FMX.Platform;

type
  TFMXSystemFontService = class(TInterfacedObject, IFMXSystemFontService)
  public
    function GetDefaultFontFamilyName: string;
  end;

function TFMXSystemFontService.GetDefaultFontFamilyName: string;
begin
  Result := 'Roboto';
end;

var
  OldInitProc: TProcedure;

procedure InitializeStyle;
begin
  if Assigned(OldInitProc) then
    OldInitProc();
  TStyleManager.SetStyle(TStyleManager.LoadFromFile('C:\Users\CCR\Downloads\Android FMX (resaved, and minus description).style'));
end;

initialization
  TPlatformServices.Current.RemovePlatformService(IFMXSystemFontService);
  TPlatformServices.Current.AddPlatformService(IFMXSystemFontService, TFMXSystemFontService.Create);
  OldInitProc := InitProc;
  InitProc := @InitializeStyle;

finalization
  TStyleManager.SetStyle(nil);
  TCanvasManager.UnInitialize;
{$ENDIF}
end.

Run the mobile preview again, and the font is now how it should be:

Font fixed


Loading the app’s icon into a TImage on Android

$
0
0

Working with Delphi for Android, I wanted to load my app’s icon into a TImage. Here’s the code I came up with:

uses
  AndroidApi.JniBridge, AndroidApi.Jni.App, AndroidApi.Jni.GraphicsContentViewText,
  FMX.Helpers.Android, FMX.Surfaces;

function GetAppIcon(Dest: TBitmap): Boolean;
var
  Activity: JActivity;
  Drawable: JDrawable;
  Bitmap: JBitmap;
  Surface: TBitmapSurface;
begin
  Result := False;
  Activity := SharedActivity;
  Drawable := Activity.getPackageManager.getApplicationIcon(Activity.getApplicationInfo);
  Bitmap := TJBitmapDrawable.Wrap((Drawable as ILocalObject).GetObjectID).getBitmap;
  Surface := TBitmapSurface.Create;
  try
    if not JBitmapToSurface(Bitmap, Surface) then
      Exit;
    Dest.Assign(Surface);
  finally
    Surface.Free;
  end;
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  GetAppIcon(Image1.MultiResBitmap[0].Bitmap);
end;

The slightly awkward manner of casting from a JDrawable to a JBitmapDrawable in the middle is because Java type casts are not supported directly by the Delphi to Java bridge. As such, we have to get a handle to the raw Java object and re-wrap it to the desired derived class… but that’s too much of a faff all told, and the syntax will be familiar with anyone who has used the Delphi to Objective-C bridge before.


Loading the app’s icon into a TImage on Windows

$
0
0

Last time I showed how to load the icon of an FMX for Android app into a TImage. In practice, a lot of the debugging of a Delphi mobile app is likely to be with a Win32 ‘mobile preview’ build though… in which case it would be useful to load the icon when running on Windows as well.

To do that, you need to first add a *.ico version to the project. This is done via Project Options: select the Application item on the left, then All configurations – 32 bit Windows platform from the combo box at the top. Probably stating the obvious, but the icon loaded here should be a .ico version of the .png files set up for Android.

Once done, the most direct equivalent of the Android code I presented previously would be to use the LoadIcon Windows API to load the icon, then GetIconInfo and so forth to get the bitmap bits to copy to a FMX bitmap. Easier is to use the VCL however – since Vcl.Graphics.pas doesn’t bring in anything else of the VCL, there’s little point in deliberately avoiding it. As such, here’s an expanded version of the code I presented last time with a VCL-based Windows implementation added:

unit AppIconLoader;

interface

uses
  System.SysUtils, System.Classes, FMX.Graphics;

function GetAppIcon(Dest: TBitmap): Boolean;

implementation

uses
  {$IF DEFINED(ANDROID)}
  AndroidApi.JniBridge, AndroidApi.Jni.App, AndroidApi.Jni.GraphicsContentViewText, FMX.Helpers.Android,
  {$ELSEIF DEFINED(MSWINDOWS)}
  Vcl.Graphics,
  {$ENDIF}
  FMX.Surfaces;

function GetAppIcon(Dest: FMX.Graphics.TBitmap): Boolean;
{$IF DEFINED(ANDROID)}
var
  Activity: JActivity;
  Drawable: JDrawable;
  Bitmap: JBitmap;
  Surface: TBitmapSurface;
begin
  Result := False;
  Activity := SharedActivity;
  Drawable := Activity.getPackageManager.getApplicationIcon(Activity.getApplicationInfo);
  Bitmap := TJBitmapDrawable.Wrap((Drawable as ILocalObject).GetObjectID).getBitmap;
  Surface := TBitmapSurface.Create;
  try
    if not JBitmapToSurface(Bitmap, Surface) then
      Exit;
    Dest.Assign(Surface);
  finally
    Surface.Free;
  end;
  Result := True;
end;
{$ELSEIF DEFINED(MSWINDOWS)}
var
  Icon: TIcon;
  Stream: TMemoryStream;
begin
  Result := False;
  Stream := nil;
  Icon := TIcon.Create;
  try
    Icon.LoadFromResourceName(HInstance, 'MAINICON');
    if Icon.Handle = 0 then Exit;
    Stream := TMemoryStream.Create;
    Icon.SaveToStream(Stream);
    Stream.Position := 0;
    Dest.LoadFromStream(Stream);
  finally
    Icon.Free;
    Stream.Free;
  end;
  Result := True;
end;
{$ELSE}
begin
  Result := False;
end;
{$ENDIF}

end.

New site ‘FMX Express’

$
0
0

Seemingly come out of nowhere, a new site has appeared that collates and summarises pretty much everything that has been posted elsewhere about everyone’s favourite roasting primate. It’s called FMX Express, so if you’re working with FireMonkey, check it out:

http://www.fmxexpress.com/


Updated FMX style for Android 4.4 (KitKat) available

$
0
0

Just a quick post to say I see Embarcadero have released an updated Android platform style for Android 4.4 (KitKat) – for more info see Sarina DuPont’s blog post here, and to download the actual style file see here.


CCR Exif v1.5.3 + Android app based on it in Google Play

$
0
0

Recently I have committed some updates to CCR Exif (my open source image metadata parsing library) that get it working with Delphi XE5, and in particular, Delphi for Android. In the main, that wasn’t hard to do – in one place I’d (mis)used the Objects property of a TStrings instance to hold casted enum values, which is a no-no under ARC, but otherwise things (with the odd [Weak] added) were fine. Well, fine with one major caveat: the code needs Andreas Hausladen’s patch to restore AnsiChar, PAnsiChar and UTF8String. Bluntly, if support for those types really does go away in XE6, then I’ll just have to say the code will support Delphi for mobile in XE5 and XE5 only, because I’m not going to crappify it.

The whole issue is a shame, because the general language and RTL compatibility between platforms (Windows/OS X/iOS/Android) and frameworks (FMX/VCL) is excellent. For example, for reading XMP metadata, my Exif code uses the IDOMxxx interfaces, the lower-level counterpart to the rather more heavyweight TXMLDocument. Both are available to use whatever the platform. Another example: at various points the FMX platform code for Android needs to wait on another thread (the Java thread) finishing a method call. What does it use for the task? Why, TEvent, using exactly the same method calls you might have made in a VCL project ten years ago.

Anyhow, proof of the pudding, I’ve written up an Exif editing app and put it on Google Play – it’s called Exif Inspector and is available here:

https://play.google.com/store/apps/details?id=com.contiguity.ExifInspector&hl=en

Brickbats welcomed, partly because you’ll have to pay a small amount to make them ;-)


Delphi (and C++Builder) XE5 ‘mobile add-on pack’ currently being discounted

$
0
0

I’ve just noticed the ‘mobile add-on pack’ for Delphi (and C++Builder) XE5 Professional is currently selling for half price on Embarcadero’s online store (link). If you’re tempted, then it’s probably prudent to buy support and maintanance at the same time, which does admittedly bump the price back up… though still not to the non-discounted price of the ‘add-on pack’ itself. Also, keep in mind the ‘mobile add-on pack’ is something specific to Delphi Professional and C++Builder Professional – if you have RAD Studio Professional or higher, or Delphi or C++Builder Enterprise or higher, then mobile support (iOS and Android for Delphi, just iOS – currently – for C++Builder) is built-in.



RemObjects release a new Oxygene version + C# sister product

$
0
0

I’ve just noticed RemObjects have released a new Oxygene version together with ‘RemObjects C#’, a C# sister product that was codenamed Hydrogene – check out the announcement here. The improved cross platform support sounds interesting (traditionally, the Oxygene language would differ somewhat depending on the target platform), and in the case of RemObjects C#… well, it seems a competitor is a bit rattled!

Miguel

Dearie me – read that and you would never guess that when it comes to targeting Android, Delphi and Xamarin are on one side of the fence and Oxygene and RemObjects C# the other, for better or for worse…

Update

And now we get this…

Hoffman

At least Delphi has done generics on OS X since 2011 ;-)


XE5 hotfix 6 is out for fixing an incompatibility with iOS SDK 7.1 and Xcode 5.1

$
0
0

Just a quick post to say Embarcadero have released hotfix 6 for XE5, which resolves significant issues when attempting to develop iOS apps in conjunction with iOS SDK 7.1 and Xcode 5.1. More info is available here; the hotfix itself is downloadable from CodeCentral here.


Knock knock…

$
0
0

A few cobwebs, but looks like everything’s still working! Can’t promise a lot more to come, but I have one or two things lined up…


Extended TClipboard implementation for FMX and VCL (CCR.Clipboard)

$
0
0

I’ve just pushed to GitHub (first time, so be gentle…) an extended, multi-platform TClipboard implementation for newer Delphi versions:

https://github.com/chrisrolliston/CCR.Clipboard

Where the platform allows, supports delayed rendering, virtual files, change notifications, and inter-process TClipboard-based drag and drop. The code originates from the FMX TClipboard I published a few years back, though is much extended, and was refactored to support the VCL too (XE2+). For more info, check out the readme first…

https://github.com/chrisrolliston/CCR.Clipboard/blob/master/Readme.md

… followed by the wiki pages for discussion of individual features, together with known issues and limitations:

https://github.com/chrisrolliston/CCR.Clipboard/wiki

Disclaimer: supporting multiple FMX versions ain’t no fun, so if you come to try it in XE4 or whatever and have an issue, I may not be able to help you. Also, if you’re interested in drag and drop on OS X, consider using my code with any version lower than XE8 a ‘proof of concept’ only…

 


CCR.PrefsIniFile on GitHub

Viewing all 62 articles
Browse latest View live