Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 06/26/23 in all areas

  1. If you need an integration for MarkDown files into Delphi apps, you can find some interesting open-source projects that I'm working on. MarkDownHelpViewer Project The MarkDownHelpViewer, is an Open-Source project to provide a Delphi-integrated help system using markdown files for online "help" creation. The project includes a ready Viewer with its setup to be installed on the user's machine (in practice the equivalent of hh.exe for the help in .chm format (see image) and an "interface" file to add to your own application that hooks the viewer to the "HelpContext" or "HelpKeyword" set on the Delphi components. Besides this also a component that can be used internally to the Delphi application to display help files. Here is the link to the project: https://github.com/EtheaDev/MarkdownHelpViewer This is a "Preview" of the viewer showing the help from the "wiki" of the InstantObjects project: There's also a small demo in the project that explains how to integrate the help with your Delphi application, including the ability to use a MarkDownViewer component right inside your application: The MarkDownShellExtensions Project In addition to the viewer, I recommend to use the MarkDown file editor, which comes with my other project available here: https://github.com/EtheaDev/MarkdownShellExtensions with which it is possible to edit the MarkDown files and immediately see the preview of the final result: Combining the two projects you will be able to offer your Delphi applications a fully integrated and easy to maintain Help system for the end user: when you need to update the images of your application because the GUI has changed, it will be sufficient to update the image on disk and update the associated markdown file, without the need for further updates, in order to always have the help updated to the latest release. Furthermore, the MarkDown format allows it to be easily published (for example as a "wiki" on Git-Hub) and is easily maintainable because it can be subjected to version-control. Those two projects are based on other Open-source projects, like: 1: SVGIconImageList: https://github.com/EtheaDev/SVGIconImageList 2: HtmlViewer: https://github.com/BerndGabriel/HtmlViewer) 2: SynEdit: https://github.com/SynEdit/SynEdit 3: VCLStyleUtils: https://github.com/RRUZ/vcl-styles-utils 4: Delphi-Markdown: https://github.com/grahamegrieve/delphi-markdown
  2. programmerdelphi2k

    Delphi Image Cropper Component?

    @Johansy in fact, you dont needs any 3rd components, you can use native controls in FMX RAD.. RAD 11.3 1 TImage to load original image / 1 to preview / 1 to cropping (for my tests) 1 TSelection to "select your area" on screen (in case, in my TImage Original image) a little code to work! if needs more actions, just do it... for example: rotations, Image1.RotationAngle := 90; ... when cropping you needs rotate the values in Rect( L,T, R, B) etc... nothing complicated at all. for "Position" on Preview or Cropping TImage, just use the coordenates X,Y... not "0,0" ... to Mobiles, use (in Selection control) a TGestureManager + events as Mouse events! type TForm1 = class(TForm) imgOriginal: TImage; Selection1: TSelection; Rectangle1: TRectangle; imgPreview: TImage; Label1: TLabel; Rectangle2: TRectangle; imgCropping: TImage; Label2: TLabel; Btn_Cropping: TButton; procedure Btn_CroppingClick(Sender: TObject); procedure Selection1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single); procedure FormCreate(Sender: TObject); procedure Selection1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); procedure Selection1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); private public end; var Form1: TForm1; implementation uses FMX.MultiResBitmap; {$R *.fmx} var LRect : TRect; LMovingMouse: boolean = false; procedure MyCroppingBitmap(ASelX, ASelY, ASelW, ASelH: Single; AImgSrc, AImgTrg: TImage); var LCBItem: TCustomBitmapItem; begin LRect := Rect(Trunc(ASelX), Trunc(ASelY), Trunc(ASelW), Trunc(ASelH)); // if AImgTrg.MultiResBitmap.Count > 1 then AImgTrg.MultiResBitmap.Clear; // always you'll have 1 Item!!! // LCBItem := AImgTrg.MultiResBitmap.Items[0]; // note: Always exists 1 item!!! LCBItem.Bitmap.Width := Trunc(ASelX + ASelW); LCBItem.Bitmap.Height := Trunc(ASelY + ASelH); LCBItem.Bitmap.CopyFromBitmap(AImgSrc.Bitmap, LRect, 0, 0); end; procedure TForm1.FormCreate(Sender: TObject); begin imgOriginal.WrapMode := TImageWrapMode.Original; // ? imgPreview.WrapMode := TImageWrapMode.Original; // ? imgCropping.WrapMode := TImageWrapMode.Original; // ? end; procedure TForm1.Selection1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin LMovingMouse := true; end; procedure TForm1.Selection1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin LMovingMouse := false; end; procedure TForm1.Selection1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single); begin if LMovingMouse then MyCroppingBitmap( { } Selection1.Position.X, { } Selection1.Position.Y, { } Selection1.Position.X + Selection1.Width, { } Selection1.Position.Y + Selection1.Height, { } imgOriginal, { } imgPreview { } ); end; procedure TForm1.Btn_CroppingClick(Sender: TObject); begin MyCroppingBitmap( { } Selection1.Position.X, { } Selection1.Position.Y, { } Selection1.Position.X + Selection1.Width, { } Selection1.Position.Y + Selection1.Height, { } imgOriginal, { } imgCropping { } ); end; initialization ReportMemoryLeaksOnShutdown := true; end.
  3. Sid D

    SBOM tool for Delphi

    Is there any tool available to create a SBOM for a Delphi Application or DLL? Thanks Sid
  4. Please don't be harsh with the comments... The principle is to identify the digits (numbers) contained in the text, add a bunch of "zeros" (to imitate the conversion into numerical values, but avoiding an "overflow" if using any text-to-number conversion function) and then represent them as their numerical value through the "ORD()" function. In this way, we avoid a possible "overflow exception", and we will be able to compare the strings (re-created for comparison purposes only) that are stored in a StringList or similar... I don't know if I managed to explain it well, but it needs testing... maybe in other languages. unit uMyTools; interface function MyNormalizeString(AStr: string; ASizeValue: byte = 10): string; function MyReCreatingMyString(AString: string): string; implementation uses System.SysUtils, System.StrUtils; const LMyDigits: TSysCharSet = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; function MyNormalizeString(AStr: string; ASizeValue: byte = 10): string; var LStr: string; LVal: string; LEnd: integer; begin LStr := ''; LVal := ''; LEnd := AStr.Length; // if not(ASizeValue in [10 .. 20]) then ASizeValue := 10; // for var i: integer := 1 to LEnd do begin if CharInSet(AStr[i], LMyDigits) then begin LVal := LVal + AStr[i]; // if ((i + 1) <= LEnd) then begin if not(CharInSet(AStr[i + 1], LMyDigits)) then begin LStr := LStr + DupeString('0', ASizeValue - LVal.Length) + LVal; LVal := ''; end; end; end else begin LStr := LStr + AStr[i]; end; end; // if not LVal.IsEmpty then LVal := DupeString('0', ASizeValue - LVal.Length) + LVal; // result := LStr + LVal; end; function MyReCreatingMyString(AString: string): string; var LStr: string; begin result := ''; // LStr := MyNormalizeString(AString); // for var C in LStr do begin if CharInSet(C, LMyDigits) then result := result + ord(C).ToString else result := result + C; end; end; end. Testing.... implementation {$R *.dfm} uses uMyTools; function MyStringListCustomSort(SL: TStringList; ALeft, ARight: integer): integer; var LCLeft, LCRight : string; CmpLeft, CmpRight: string; begin LCLeft := LowerCase(SL[ALeft]); LCRight := LowerCase(SL[ARight]); // CmpLeft := MyReCreatingMyString(LCLeft); CmpRight := MyReCreatingMyString(LCRight); // result := CompareStr(CmpLeft, CmpRight); // if (result = 0) then result := CompareStr(LCLeft, LCRight); end; procedure TForm1.Btn_CustomSortClick(Sender: TObject); var SL: TStringList; begin Memo1.Lines.Clear; // SL := TStringList.Create; try SL.Sorted := false; SL.Duplicates := TDuplicates.dupAccept; // SL.Add('Delphi1World1Hello Windows'); // 1 space SL.Add('hello2'); SL.Add('hello10'); SL.Add('hello1'); SL.Add('hello4'); SL.Add('delphi 2'); // 2 spaces SL.Add('hello 000'); // 1 space SL.Add('delphi'); SL.Add('hello3'); SL.Add('Delphi3 World2023'); // 1 space SL.Add('Custom'); SL.Add('delphi 2'); // 1 space SL.Add('Delphi1.5World10 11'); // 1.5 - 1 space SL.Add('World'); SL.Add('Delphi 1'); // 1 space SL.Add('A B C'); // 1 space + 1 space SL.Add('hello000'); // 0 space SL.Add('abc'); SL.Add('delphi 2'); // 1 space SL.Add(''); // EMPTY!!! SL.Add('Delphi10'); SL.Add('Delphi1'); SL.Add('Delphi13'); SL.Add('Delphi1.5World10 21'); // 1.5 - 1 space SL.Add('Delphi001'); SL.Add('Delphi3'); SL.Add('Delphi3World2023'); SL.Add('Delphi3 Hi!'); // 1 space SL.Add('Delphi 5'); // 1 space SL.Add('Delphi1.2World1Hello Windows'); // 1 space SL.Add('Delphi2'); SL.Add('Delphi01'); SL.Add('Delphi 3World2023'); // 1 space SL.Add('Delphi 1'); // 1 space SL.Add('Delphi12'); SL.Add('Delphi4'); SL.Add('Delphi2.5World2022'); // 2.5 SL.Add('Hello3.5'); // SL.CustomSort(@MyStringListCustomSort); // Memo1.Lines.AddStrings(SL); finally SL.Free; end; end; initialization ReportMemoryLeaksOnShutdown := true; end.
  5. programmerdelphi2k

    TListBox - grouping of items and horizontal scroll bar

    code fixed!!!
  6. programmerdelphi2k

    TListBox - grouping of items and horizontal scroll bar

    @kaarigar you can try some like this: FIXED implementation {$R *.fmx} procedure TForm1.Btn_Create_ItemsClick(Sender: TObject); const LHeaders: array [0 .. 2] of string = ('Header1', 'Header2', 'Header3'); var LBGHeader : TListBoxGroupHeader; LBGHeaderHeight: single; LBItem : TListBoxItem; LBItemHeight : single; LItemHeight : single; LHowManyItems : integer; begin // reset all default values... ListBox1.Clear; ListBox1.ItemHeight := 0; ListBox1.ListStyle := TListStyle.Vertical; ListBox1.Columns := 1; // LBGHeaderHeight := 19; // default values LBItemHeight := 19; LHowManyItems := 1; // for var i: integer := 0 to high(LHeaders) do // if headers with distinct height, then needs some calc... begin LBGHeader := TListBoxGroupHeader.Create(Self); LBGHeader.Text := LHeaders[i]; ListBox1.AddObject(LBGHeader); LBGHeaderHeight := LBGHeader.Height; // here you can verify if a Header is > than before // LHowManyItems := Trunc(SpinBox1.Value); // for var j: integer := 1 to LHowManyItems do begin LBItem := TListBoxItem.Create(Self); LBItem.Text := '... Item' + j.ToString; ListBox1.AddObject(LBItem); LBItemHeight := LBItem.Height; // if Item with distinct height, then needs some calc... end; end; // LItemHeight := ListBox1.ClientHeight - (LBGHeaderHeight + 1); // (LBGHeaderHeight + 1 = line-separator LItemHeight := (LItemHeight / (LHowManyItems + 1)); // LHowManyItems + Header // ListBox1.ItemHeight := LItemHeight; ListBox1.ListStyle := TListStyle.Horizontal; end; initialization ReportMemoryLeaksOnShutdown := true; end.
  7. Seems unlikely that MS would break its system because some people write crap programs.
  8. Firstly, let me say that my work on SynEdit has moved back to pyscripter/SynEdit for reasons explained here. The newest enhancement to SynEdit is accessibility support. Now, SynEdit fully supports screen readers such as Windows Narrator and NVDA. The support is much better than, for instance, in Visual Studio Code. The implementation is not based on the older Microsoft Active Accessibility (MSAA), but on the newer Microsoft UI Automation. Microsoft UI Automation has been around since 2005 and is available to all Windows versions, since Windows XP. In addition to making applications accessible, it can also be used by automated UI testing tools. Despite been available for almost 20 years, Delphi does not provide the relevant header translations (See RSP-41898), which complicated the implementation. I also could not find any other complete Delphi implementation of UI automation. So, the SynEdit implementation may serve as a guide to how to implement UI Automation in other controls. Further details can be found here.
  9. I think that no really needs "MyReCreatingMyString( ... )" at all... you can delete it!!! Now, let's study "Natural Sort Order..." ... 🙂 unit uMyTools; interface function MyNormalizeString(AStr: string; AValLength: byte = 10): string; implementation uses System.SysUtils, System.StrUtils; const LMyDigits: TSysCharSet = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; function MyNormalizeString(AStr: string; AValLength: byte = 10): string; var LStr: string; LVal: string; LEnd: integer; begin LStr := ''; LVal := ''; LEnd := AStr.Length; // { ex. Text1 and Text1234567890 and Text123456789012345 = part complex!!! AValLength := ? Text0000000001 Text1234567890 Text123456789012345 // ... we can have it with distinct length, then we use an arbitrary value! } if (AValLength < 10) then AValLength := 10 else if (AValLength > 20) then AValLength := 20; // for var i: integer := 1 to LEnd do begin if CharInSet(AStr[i], LMyDigits) then begin LVal := LVal + AStr[i]; // if ((i + 1) <= LEnd) and not(CharInSet(AStr[i + 1], LMyDigits)) then begin LStr := LStr + DupeString('0', AValLength - LVal.Length) + LVal; LVal := ''; end; end else LStr := LStr + AStr[i]; end; // if not LVal.IsEmpty then LVal := DupeString('0', AValLength - LVal.Length) + LVal; // result := LStr + LVal; end; end. function MyStringListCustomSort(SL: TStringList; ALeft, ARight: integer): integer; var LCLeft, LCRight : string; CmpLeft, CmpRight: string; begin LCLeft := LowerCase(SL[ALeft]); LCRight := LowerCase(SL[ARight]); // CmpLeft := MyNormalizeString(LCLeft); CmpRight := MyNormalizeString(LCRight); // result := CompareStr(CmpLeft, CmpRight); // if (result = 0) then result := CompareStr(LCLeft, LCRight); end;
  10. It would be cool to look at the Wine implementation of StrCmpLogicalW and port that to Pascal once and for all for a cross platform implementation. https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/kernelbase/string.c#L1298 Looks kinda simple really
  11. It's called "Natural" sort order. Explorer probably uses StrCmpLogicalW but there's also CompareStringEx with SORT_DIGITSASNUMBERS? See also: Sorting for Humans : Natural Sort Order
  12. Rollo62

    VCL Wrap

    Wouldn't it be more clean to use the interposer without the intermediate class wrapper TSuperButton ? https://zarko-gajic.iz.hr/delphi-interceptor-classes-tbutton-classtbutton/ type TButton = class(stdctrls.TButton) private fLastClickTime: TDateTime; public procedure Click; override; public property LastClickTime : TDateTime read fLastClickTime write fLastClickTime; end;
  13. Fr0sT.Brutal

    VCL Wrap

    TSuperButton = class(TButton) ... end; TButton = TSuperButton // ! the trick Tform1 = class(TForm) btn: TButton; // <- will be TSuperButton in fact Type reassignment trick
  14. FPiette

    VCL Wrap

    If you want access to the properties and events at design time, there is no other way than creating and installing a new component having those properties and events. If you want access the properties and events only at runtime, then no need to create a component. Just create a new class deriving from some ancestor and add the properties and events.
×