Jump to content

Alexander Halser

  • Content Count

  • Joined

  • Last visited

  • Days Won


Alexander Halser last won the day on September 17

Alexander Halser had the most liked content!

Community Reputation

18 Good

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Alexander Halser

    Cross-platform Application Help for FMX and VCL

    A personal preference, no technical obstacle. A mobile app I want to be lean and small. So, I'd put the help system on the app's website and let it refer to the online version, displaying the help in the regular system browser. The demo has an option that illustrates this (though the demo uses its internal TWebBrowser to display the result). In other words: I would not use the zip functionality for a mobile app and rather remove the reference to system.zip in ziphelp.pas for those platforms with a compiler switch (plus the single line that uses it). The rationale behind this consideration is that a mobile app goes to one of the stores and automated updates are very likely, minimizing the risk of a version mismatch between app and help. Furthermore I expect a mobile device to be online anyway. Both points may not apply to a desktop app. But it's really a personal preference.
  2. Alexander Halser

    Cross-platform Application Help for FMX and VCL

    No, it is not derived from CHM. Because CHM is basically Windows only and not cross-platform. Yes. plain HTML5 and based on the regular "sitemap" XML schema. When you create CHM files for a Windows application, you typically use an authoring tool for this and don't craft the HTML in Notepad. Those authoring tools which create CHM files usually create plain HTML5 as well. The example help you see in the demo project was created with Help+Manual, it's plain vanilla HTML5 and Javascript. But not just Help+Manual produces this output, Madcap Flare does, Adobe Robohelp does, you name it. And most authoring tools offer some kind of syntax to use the plain HTML5 output for context-sensitive help. Unfortunately, everyone has their own syntax, there is no established standard. And because of a missing standard, there are no viewer applications, as long as everyone does their own thing. Ziphelp is an attempt and a ready-to-use solution for this dilemma. It is as open as possible, because it is based on the standard sitemap protocol. This is the same sitemap.xml that you use on your website to help Google index it. Ziphelp is basically a legal extension of this protocol. Open for everyone to produce content that includes a Ziphelp sitemap and open for everyone to create an HTML viewer that can read it. To give it a head start, we have created a freely distributable HTML viewer that reads the Ziphelp protocol (https://www.helpandmanual.com/ewriter/). Some people prefer this solution because it's less work for them. But for Delphi developers, I think that a native cross-platform implementation is more appealing. Here, everything is under your control and your application can interactively question the help system if it actually "supports help context number 45327" or if that number is outdated in the UI of your app (and you should clean it up, but at least you don't let your end users run into an 404 error). This interactivity is missing even with CHM files. So, here you go. A free Delphi implementation that supports HTML5 in a zip archive, uncompressed HTML or web-based content. It all works with the same protocol and the same mechanism, on all platforms. You can create this HTML5 help system with our tool Help+Manual, of course. But you don't have to. If you prefer a different authoring tool, go for it.
  3. Alexander Halser

    Cross-platform Application Help for FMX and VCL

    The project now has been moved to Sourceforge: Delphi Cross-Platform Application Help download | SourceForge.net
  4. We have just released an open-source Delphi implementation for a HTML-based cross-platform application help system. Information page: Ziphelp - an open cross-platform help format Direct download link: https://www.helpandmanual.com/download/delphi-ziphelp-demo-source.zip About Ziphelp On the surface, Ziphelp is basically HTML in a compressed zip archive, hence the name. Pack any folder with HTML files into a zip archive and you are good to go. But Ziphelp is more than that, it is a protocol based on the standard sitemap protocol, designed to give a help viewer (here: the Delphi implementation) extended information about the content of the help system. That is help context numbers, help keywords, associative keywords, page titles. This information is missing in a standard sitemap.xml. Ziphelp extends the sitemap protocol and enables direct communication of an app with the help system. The Ziphelp protocol is not just for zip archives. It works inside an archive, with uncompressed folders or with HTML content loaded directly from a website. A Delphi desktop app may be deployed with local application help, uncompressed, zipped or embedded. A mobile or web application might not ship with local HTML content, but refer to an online version instead. The mechanism is the same in both cases and the TZiphelp component implements this for Delphi. Demo Application A demo app for VCL and FMX (Win/MacOS) is included. The demo builds on standard Delphi components (TWebBrowser) to display the help system.
  5. Alexander Halser

    A popup color selector for Windows and MacOS

    The color selector has been updated to v1.3 on SourceForge. A couple of features added, some bugs fixed. https://sourceforge.net/projects/delphi-fmx-color-selector/files/
  6. It really does? I wasn't aware of that. Maybe we have just been lucky and were always using that one DrawImage method, that works. We draw pictures with the GDI+ function below. Bounds is the destination rectangle, already calculated in device pixels. procedure DoGDIPlusDraw(DC: HDC; bmp: TBitmap; bounds: TRect); var gpgraphics: TGPGraphics; gpimage: TGPBitmap; Width, Height: UINT; begin gpgraphics := TGPGraphics.Create(DC); gpimage := TGPBitmap.Create(bmp.Handle, bmp.palette); try Width := gpimage.GetWidth; Height := gpimage.GetHeight; gpgraphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); // 7 gpgraphics.DrawImage(gpimage, bounds, // destination rectangle 0, 0, // upper-left corner of source rectangle Width, // width of source rectangle Height, // height of source rectangle UnitPixel); finally gpimage.Free; gpgraphics.Free; end; end;
  7. Without trying your example ... When you print an image, the screen DPI doesn't matter at all. You are dealing with printer DPI instead. Nothing else. TGPBitmap loads the PNG image and that image has a defined size in pixels. With TGPBitmap.DrawImage the picture is rendered onto a Windows device, which can be a screen device or a printer device. For GDI+ this is more or less the same (some technical printer details omitted). Fact is, GDI+ does the stretching and resampling to make the image fit into the rectangle you specify. And that target rectangle must be in device pixels. If the device is a printer, get LOGPIXELSX from the printer canvas and relate it to 96 dpi (= Windows standard display resolution at 100%). // get printer device DPI DC := GetDC(Printer.Canvas.Handle); try nLogPx := GetDeviceCaps(DC, LOGPIXELSX); memo1.Lines.Add(Format('Printer Device: %d', [nLogPx])) finally ReleaseHDC(DC); end; rectImage.Create( MulDiv(10, nLogPx, 96), MulDiv(10, nLogPx, 96), MulDiv(100, nLogPx, 96), MulDiv(100, nLogPx, 96) ); (The code example is untested, typed from memory. Point is, get the resolution of the printer canvas, not the screen.)
  8. Alexander Halser

    How do I know if the click is an actual user click ?

    That doesn't apply to checkboxes alone. Radio buttons, radio groups, checked menu items, actions, OnResize events, you name it. Some forms have plenty of details to initialize. We have been using update counters for that, since more than 20 years. Like, every TForm that does some initialization which may auto-trigger events, has an IsUpdating property. The setter increases/decreases the value, the getter returns a boolean. If IsUpdating returns true (> 0), the checkboxes do not execute their OnChange event, manually arranged panels do not update, etc. constructor TForm1.Create(AOwner: TObject); begin inherited; FIsUpdating := 0; IsUpdating := true; //increases FIsUpdating try //do your init here finally IsUpdating := false; end; end; procedure TForm1.SetIsUpdating(value: boolean); begin if value then inc(FIsUpdating) else dec(FIsUpdating); end; function TForm1.GetIsUpdating: boolean; begin result := FIsUpdating > 0; end; A counter is more flexible and error-tolerant than using the csUpdating flag in ComponentState. It can be used to update corresponding controls in an OnChange event as well, without triggering their OnChange. The counter enables nested IsUpdating without worries. The only thing to remember is to consequently use try-finally.
  9. Alexander Halser

    Work with PDF documents

    PDFium lib does all you need. We use it with an internal application that deals with PDF pages. Add or remove pages, split pages into several smaller ones, re-combine smaller pages into one printer page. PDFium can extract text as well.
  10. Alexander Halser

    Mouse events not triggered, caused by styled TMainMenu?

    tested with polardark_win and polarlight_win styles I confirm that it works for me with the styles included in Delphi and those premium styles available for download when you have an active subscription. That's why I asked the OP where the dark styles origins from. Maybe it is an older style? My argument is that if a simply outdated style compiles just fine and looks good on screen, but generates potential runtime issues that may cause problems I would have never expected and that are difficult to find, then we're in for future problems with FMX styles
  11. Alexander Halser

    Mouse events not triggered, caused by styled TMainMenu?

    ChildForm is not released, StyleBookLight don't contain data Where do you see a problem here? Form2 is auto-created and auto-released, StyleBookLight is not required to produce the problem. I had some similar problem using an old 10.2 style That worries me ... what happens if a project that includes a TStylebook with a previously up-to-date style gets updated to a new Delphi version? Does that mean it compiles just fine but fails at runtime with mysterious errors? How does one test an app for potential problems like the one above? I'd like to know where it comes from before using FMX styles.
  12. Alexander Halser

    Mouse events not triggered, caused by styled TMainMenu?

    Fascinating example... thanks a lot! I am currently experimenting with FMX styles and very much appreciate this. It's got something to do with the dark style - the style itself damages the runtime functionality. I can duplicate the issue with Delphi 11.0, both 32 and 64 bit, it is reproducible with the dark style (only). Switching back to the light style makes it work again. My first guess was that it has to do with TStyleBook. It is apparent that the second form does not pick up the style, so I thought it may have to do with this issue. But this is not the case. So I loaded my own dark skin into your dark stylebook. Guess what? Works like a charm, despite not applying the style to the second window. There is, that's for sure, some flaw in the dark style you are using. Fascinating this is possible at all... I did not think it was. Where does your dark style come from?
  13. Alexander Halser

    Detecting MouseUp When Outside The Form

    FMX doesn't auto-capture the control the mouse went down on. But you can do this manually, either by TForm.MouseCapture (that's for the form itself) or with TForm.SetCaptured(AnyControl) - this is for a particular control on the form. procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin if (Sender <> self) then SetCaptured(TControl(Sender)) else MouseCapture; memo1.lines.add(Sender.Classname + ' mouse down'); end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin ReleaseCapture; memo1.lines.add(Sender.Classname + ' mouse up'); end; Setting the mouse capture is important if you do anything in MouseDown that interacts with the control being clicked. Without capture, the user may click (mouse-down) on Panel1, move it, and release it on Panel2. The MouseUp will come from Panel2 in this case, or no mouse-up at all. By setting the mouse capture, you are guaranteed that you'll receive a MouseUp from that control that is being captured. VCL does this automatically, FMX does not. If you don't need the MouseDown on form level, but just for particular controls, use TControl.AutoCapture instead.
  14. Alexander Halser

    A popup color selector for Windows and MacOS

    For a new FMX app (Win/Mac only), I need some UI controls that go beyond the simple features that the Delphi built-in controls have to offer. One of them is a color picker component. There are very few color picker tools available for FMX and creating a new one turned out to be more work than anticipated. That's why I put mine on SourceForge. If you require a similar control, feel free to use it as you please. Delphi FMX Color Selector download | SourceForge.net I hope to get some feedback on the component as well, because it currently has 2 flaws (explained below). To use the color picker, reference the unit and call one of the two global methods ColorDropdown and ColorButtonDropdown. The first method is generic and can be used with any control, the second expects a standard TColorButton. I have implemented the component in a TForm that is dynamically created at runtime. No component installation required. This was an important point [for me], because I need a few more very specialized popup controls that are supposed to be placed in this form. Using a simple TForm makes it much easier to design them than doing everything in code. Current issues: One of the obstacles I came across was a drawing bug in TGrid, at least with Delphi 11.0 (maybe fixed in later versions). The grid is/was designed to fit exactly 10 rows and on the first display, it properly shows all 10 rows. Close and reopen the popup control, and the original 10 rows have shrunken to 9 visible rows. I fixed it by making the grid tall enough for 11 rows and filled the whitespace below by moving the opacity slider up. Looks fine and works so far, but if someone has an idea how to fix the visible rows in TGrid, I would appreciate a feedback. The second issue is the color picker. It's implemented as a picture that you can drag & drop anywhere on the parent form to pick a color. This method is safe, but not 100% intuitive. A click-button-then-select-color function would be nicer. So, if anyone wants to spend time on that, I appreciate it. Apart from that, have fun trying it - demo application is included.
  15. Alexander Halser

    Access TStringGrid InplaceEditor

    I was about to suggest to create a custom inplace editor. But the form that contains the TStringGrid does get KeyDown notifications, even when editing content. Out of curiosity, I wanted to know the internal structure of the grid, when it's editing. procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); var ctl: tfmxobject; s: string; begin if key = vkF5 then begin ctl := activecontrol; while ctl <> form2 do begin s := '> ' +ctl.classname + S; ctl := ctl.Parent; end; showmessage(s); end; end; It says: TStringGrid > TGridScrollContent > TDefaultEditor So if you check the OnKeyDown on form level and detect that ActiveControl is a TDefaultEditor with a TStringGrid as grandparent, you should be all set. Aren't you?