Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by balabuev

  1. I tried to keep the code reasonably simple. Yes, sure, some improvements are possible. Instead of objects we can at least use records for map items with New/Dispose (or even better, with GetMem/FreeMem), as @Stefan Glienke mentioned before (if I've understood right). We can also go futher and try to minimize heap allocations, or use some sort of map item pool, etc. We also can use some initial capacity as you propose. But, this will complicate the demo code, thus, hiding the main idea, which it tries to show. Moreover, map filling is not critical for this particular test. We measure only search speed.
  2. Does anyone know which tool Embarcadero uses itself to generate source code documentation (reference)?
  3. balabuev

    Documentation creation tool

    All this is very funny, but the question remains open. We are searching for appropriate source code documentation tool (except Documentation Insight, which we already know about), which is not outdated, and preferably allows to keep documentation separately from the code.
  4. This is the key line. Now let's think, where this strange "-32000" numbers may araise at all. I'm sure 99.9% that the numbers are received from a Windows API function call, such as GetWindowRect (or similar) in minimized window state (IsIconic(Handle) = True). Simple experiment proves it: procedure TForm1.Timer1Timer(Sender: TObject); var wr: TRect; begin if WindowState = TWindowState.wsMinimized then begin GetWindowRect(Handle, wr); OutputDebugString(PChar(wr.Left.ToString + ', ' + wr.Top.ToString)); end; end; So: With "-32000" left and top values the window is not, of course, within the area of your monitor 1, but this monitor becomes the closest one to the window.
  5. Handling of maximized form state is bugfull even without multi-monitor setup, and even without VCL Styles. Use the following code with a simple memo on a form: procedure TForm1.FormResize(Sender: TObject); begin Memo1.Lines.Add(Width.ToString + ', ' + Height.ToString + ', ' + IsIconic(Handle).ToString); end; Run the project and maximize the form. Minimize the form using taskbar app button. Maximize it back using taskbar app button. You will see that during minimize/maximize steps two OnResize events are fired with different Width/Height values. This was not the case in early Delphi versions, like Delphi 7; this was introduced later along with the Application.MainFormOnTaskbar feature. I'm sure that all such issues are related, and the problem is that they forget to check for IsIconic() whenever appropriate.
  6. I can confirm the issue with the configuration similar to yours: Monitor 1 - 100% (primary) Monitor 2 - 125% App's main form is shown on the primary monitor (1). The bug happens if monitors are related like this (monitor 2 has negative X coordinates in its area) The bug does not happen if monitors are related like this:
  7. Well, several posts above, @vfbb (topic starter) mentioned TEdit as an exmple "to clarify the problem", which is obviously uses text rendering.
  8. Not fully agree. You still has to rely on OS text rendering features. Which are themselfs depend on ICU. So, your own ICU can be not well consistent with OS's one, which is used for rendering.
  9. The official APIs in Windows to deal with Unicode stuff - is Uniscribe. It allows to decode Unicode related information from a Utf16 string. Including the sequence of glyphs for rendering. But, what you will do with them? Because, every glyph is denoted as a number, without any meaningfull value; and you can only pass this sequence to ExtTextOut. Also, Uniscribe provides supporting attributes to Unicode codepoints, such as: whether it's a wrod start (for Ctrl+Left/Right navigation) whether it's a word end a valid caret positions (some codepoints are not valid caret positions) should the codepoint be deleted as a group with neightboord codepoints etc. All rules are complex and different from each other. There no simple way to move editor caret and select the text in Unicode enabled text editor. I suggest the following old and great tutorial (an attempt to create the editor with Unicode support) http://www.catch22.net/tuts/neatpad/introduction-uniscribe#
  10. balabuev

    caFree & ,Free??

    As recently has been mentioned in another thread, it's only safe if the code inside try/finally do not occasionally (or indirectly) call Application.ProcessMessages after ShowModal: MyForm := TMyForm.Create(...); try MyForm.ShowModal; Application.ProcessMessages; // Or SomeAnotherForm.ShowModal, etc. finally MyForm.Free; end; In this case the form may be freed via CM_RELEASE, and then - freed the second time via the code in finally block.
  11. balabuev

    Creating sub nodes with debugger visualizer

    Also, I've noticed that the strings are different in code editor drop-down and in local variables view: String in code editor drop-down seems to be more complete (like it should be returned from GetReplacementValue). While the string in local variables view seems to be already processed by IDE.
  12. balabuev

    Creating sub nodes with debugger visualizer

    Never tried it myself, but I suspect that you just need to return a string with specific format. Such as "(3, 5, 7)" to show value as array with child elements. Or like "(PropA: 3; PropB: 5)" to show as object with child properties. I may be wrong, of course. Do you looked at the source code of TDebuggerListHelperVisualizer.GetReplacementValue?
  13. This happens (and always was the case) with the following settings:
  14. balabuev

    Delphi WAT of the day

    Task completed:
  15. balabuev

    Object Inspector issue in 10.4.2??

    Then, I don't know, sorry.
  16. balabuev

    Object Inspector issue in 10.4.2??

    Try to uninstall third-party stuff. Like Cnpack/Gexperts... Also your object instector looks strange. I have no horizontal lines:
  17. balabuev

    Object Inspector issue in 10.4.2??

    Non-standard property editors are installed. More technically (if anyone interested) this happens when a property editor implements ICustomPropertyDrawing interface but does not implement more recently introduced ICustomPropertyDrawing80 interface.
  18. balabuev

    VCL Handling of dpi changes - poor performance

    My point is that from all things, happening during rescaling of a form, the most resource consuming are SetWindowPos calls, which are called from SetBounds, which are themselfs called from different places, including AlignControls. Drawing and especially async invalidation takes much less resources and time, imho. So, when we speak about form rescaling performance, we can denote it as O(n), where n - is mostly the number of SetWindowPos calls. To trace how many times SetWindowPos is actually called we can use WM_WINDOWPOSCHANGED event handlers on child controls. So, given very simple example with a single TPanel control, aligned with alClient on a form, I see three SetWindowPos on each dpi boundary cross: procedure TPanel.WMWindowPosChanged(var M: TWMWindowPosChanged); var cr: TRect; begin if (M.WindowPos.flags and SWP_NOSIZE) = 0 then begin Winapi.Windows.GetWindowRect(Handle, cr); OutputDebugString(PChar('WMWindowPosChanged: ' + cr.Width.ToString + ',' + cr.Height.ToString)); end; inherited; end; As seen from the events log the child panel is repositioned three times, and each time its size is set to different value: 638 * 380 510 * 304 640 * 382 So, in this particular case three times more work is done, than it actually required. Test project: dpi_test.zip PS: Looking more generally at this issue I have to conclude that layouting should be asynchronous. The concept of async layouting is a some kind of replacement of the global BeginUpdate/EndUpdate mentioned earlier. But, this will be too big and breaking change for VCL. And moreover, this is almost impossible for native Windows controls, such as TEdit, TListBox, etc.
  19. balabuev

    VCL Handling of dpi changes - poor performance

    In my demo on a form full of different controls this line is not executed at all.
  20. balabuev

    VCL Handling of dpi changes - poor performance

    Those issues in VCL are unfixable.
  21. Sorting of replacement patterns (by length, desc) seems to me an overkill. As @Attila Kovacs already proposed, input patterns already have their natural order in array - so this order should be respected. This will be more flexible, and fast.
  22. Here is my small idea. Not perfect, has limitations, I guess, but usable {$POINTERMATH ON} const GUESS_MASK = 32 - 1; procedure BuildGuess(AGuess: PByte; const aOld: array of string); var pi, j: Integer; begin FillChar(AGuess^, GUESS_MASK + 1, 0); for pi := 0 to High(aOld) do begin j := Ord(aOld[pi][1]) and GUESS_MASK; if AGuess[j] = 0 then AGuess[j] := pi + 1 else AGuess[j] := 255; end; end; function Equals(S1, S2: PChar; ACount: Integer): Boolean; var i: Integer; begin for i := 0 to ACount - 1 do begin if S1[i] <> S2[i] then Exit(False); end; Result := True; end; function MyReplace(const S: string; const aOld, aNew: array of string): string; label L; var lnt: Integer; pcnt: Integer; c, eof: PChar; p: PChar; pi, j: Integer; pln: Integer; off: Integer; guess: array[0..GUESS_MASK] of Byte; begin pln := 0; lnt := Length(S); pcnt := Length(AOld); BuildGuess(@guess, aOld); SetLength(Result, lnt * 2); c := Pointer(S); eof := c + lnt; off := PChar(Pointer(Result)) - c; while c <> eof do begin pi := guess[Ord(c^) and GUESS_MASK]; if pi <> 0 then begin if pi <> 255 then begin Dec(pi); pln := aOld[pi].Length; if (c^ = aOld[pi][1]) and Equals(c, Pointer(aOld[pi]), pln) then goto L; end else begin pi := 0; while pi <> pcnt do begin pln := aOld[pi].Length; if (c^ = aOld[pi][1]) and Equals(c, Pointer(aOld[pi]), pln) then goto L; Inc(pi); end; end; end; c[off] := c^; Inc(c); Continue; L: Inc(c, pln); Dec(off, pln); pln := aNew[pi].Length; p := Pointer(aNew[pi]); for j := 0 to pln - 1 do c[off + j] := p[j]; Inc(off, pln); end; SetLength(Result, @c[off] - PChar(Pointer(Result))); end;
  23. balabuev

    TTreeNode leak when VCL styles are active