Jump to content

Mike Torrettinni

Members
  • Content Count

    1509
  • Joined

  • Last visited

  • Days Won

    3

Posts posted by Mike Torrettinni


  1. thanks @Remy Lebeau I went a little different - with TSplitter interposer:

     

    // Splitter interposer
    TSplitter = class(Vcl.ExtCtrls.TSplitter)
      private
        var fOriginalWindowProc: TWndMethod;
        var fOtherSplitter: TSplitter;
        var fMovingControl: TSplitter;
      public
        procedure MoveOtherSplitter(var aMsg: TMessage);
      end;
    
    procedure TSplitter.MoveOtherSplitter(var aMsg: TMessage);
    begin
      if  (fMovingControl = nil) or (fMovingControl = Self) then
      Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
        begin
          fMovingControl := Self;
          fOtherSplitter.fMovingControl := Self;
          fOtherSplitter.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
          fMovingControl := nil;
          fOtherSplitter.fMovingControl := nil;
        end;
      end;
      fOriginalWindowProc(aMsg);
    end;

     

    And assigning method:

     

    procedure LinkSplitters(aSplitter1, aSplitter2: TSplitter);
    begin
      aSplitter1.fOriginalWindowProc := aSplitter1.WindowProc;
      aSplitter1.WindowProc := aSplitter1.MoveOtherSplitter;
      aSplitter1.fOtherSplitter := aSplitter2;
    
      aSplitter2.fOriginalWindowProc := aSplitter2.WindowProc;
      aSplitter2.WindowProc := aSplitter2.MoveOtherSplitter;
      aSplitter2.fOtherSplitter := aSplitter1;
    end;

     

    the I can just use simple LinkSplitters:

     

    LinkSplitters(Splitter1, Splitter2);

     

     


  2. It could be improved, but this if how I made it work:

     

    splittersOK.gif.30e14059e8728e60807bb7da5efc9e45.gif

     

    new variable that gets assigned by moving control:

    var fMovingControl: TObject;

     

    and new move methods:

     

    procedure TForm1.MoveOtherSplitter(var aMsg: TMessage);
    begin
     if  (fMovingControl = nil) or (fMovingControl = Splitter1) then
     Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
        begin
          fMovingControl := Splitter1;
          Splitter2.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
          fMovingControl := nil
        end;
      end;
      fOriginalWindowProc(aMsg);
    end;
    
    procedure TForm1.MoveOtherSplitter2(var aMsg: TMessage);
    begin
     if (fMovingControl = nil) or (fMovingControl = Splitter2) then
      Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
         begin
          fMovingControl := Splitter2;
          Splitter1.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
          fMovingControl := nil;
         end;
      end;
       fOriginalWindowProc2(aMsg);
    end;

     

    I tried to make it more generic, but TMessage doesn't have Sender, so I can't identify which control send the Perform message. 


  3. 9 minutes ago, Lajos Juhász said:

    Why not use the OnMoved event of the splitter?

     

    4 minutes ago, Attila Kovacs said:

    OnAlignInsertBefore

    OnAlignPosition

     

    I think these suggestions will not work because I want the both splitters to move at the same time, not when moving is done.

     

    See the behavior:

     

    splitters.gif.e1d96cd8f720cf1cea61a93e9251d4fb.gif


  4. I have 2 splitters that I would like to synchronize moves, to move at the same time.

    Here I have example of top and bottom 2 panels, and 2 splitters:

     

    image.png.5350e01a109e24684999f8efbd7523eb.png

     

    When Splitter1 resizes Panels 1&2, I would like for Splitter2 to resize Panels 3&4 at the same time, as if it's 1 splitter. Horizontal splitter of course splits Up & Down areas, so I can't have 1 vertical splitter.

     

    I found this code (http://www.delphigroups.info/2/66/312669.html) and works good for just 1 splitter. It works good when moving Splitter1 it also moves the same way Splitter2.

     

    TForm1
    private
        fOriginalWindowProc: TWndMethod;
        procedure MoveOtherSplitter(var aMsg: TMessage);
    ...
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      fOriginalWindowProc := Splitter1.WindowProc;
      Splitter1.WindowProc := MoveOtherSplitter;
    end;
    
    procedure TForm1.MoveOtherSplitter(var aMsg: TMessage);
    begin
      Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
          Splitter2.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
      end;
       fOriginalWindowProc(aMsg);
    end;

     

    But I don't know how to modify the code to apply the same behavior when moving Splitter2 to move Splitter1 at the same time.

     

    I tried to assign similar to Splitter2:

     

    var fOriginalWindowProc2: TWndMethod;
        procedure MoveOtherSplitter2(var aMsg: TMessage);
    ...
    fOriginalWindowProc2 := Splitter2.WindowProc;
    Splitter2.WindowProc := MoveOtherSplitter2;
    
    procedure TForm1.MoveOtherSplitter2(var aMsg: TMessage);
    begin
      Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
          Splitter1.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
      end;
       fOriginalWindowProc2(aMsg);
    end;

     

    I get stack overflow, because it locks in a message loop between both splitters moves.

     

    Any help appreciated in implementing how to synchronize splitters.

     

    full code with form:

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;
    
    type
      TForm1 = class(TForm)
        Panel1: TPanel;
        Panel2: TPanel;
        Splitter3: TSplitter;
        Panel3: TPanel;
        Panel4: TPanel;
        Splitter1: TSplitter;
        Panel5: TPanel;
        Panel6: TPanel;
        Splitter2: TSplitter;
        procedure FormCreate(Sender: TObject);
      private
    
        fOriginalWindowProc: TWndMethod;
        procedure MoveOtherSplitter(var aMsg: TMessage);
    
        var fOriginalWindowProc2: TWndMethod;
        procedure MoveOtherSplitter2(var aMsg: TMessage);
    
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      fOriginalWindowProc := Splitter1.WindowProc;
      Splitter1.WindowProc := MoveOtherSplitter;
    
      fOriginalWindowProc2 := Splitter2.WindowProc;
      Splitter2.WindowProc := MoveOtherSplitter2;
    end;
    
    procedure TForm1.MoveOtherSplitter(var aMsg: TMessage);
    begin
      Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
          Splitter2.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
      end;
       fOriginalWindowProc(aMsg);
    end;
    
    procedure TForm1.MoveOtherSplitter2(var aMsg: TMessage);
    begin
      Case aMsg.Msg Of
        WM_MOUSEFIRST..WM_MOUSELAST:
          Splitter1.Perform(aMsg.Msg, aMsg.WParam, aMsg.LParam);
      end;
       fOriginalWindowProc2(aMsg);
    end;
    
    end.
    
    
    
    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 360
      ClientWidth = 477
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -12
      Font.Name = 'Segoe UI'
      Font.Style = []
      OnCreate = FormCreate
      TextHeight = 15
      object Splitter3: TSplitter
        Left = 0
        Top = 180
        Width = 477
        Height = 3
        Cursor = crVSplit
        Align = alTop
        Color = clActiveCaption
        ParentColor = False
        ExplicitLeft = 1
        ExplicitTop = 1
        ExplicitWidth = 832
      end
      object Panel1: TPanel
        AlignWithMargins = True
        Left = 3
        Top = 3
        Width = 471
        Height = 174
        Align = alTop
        BevelOuter = bvNone
        ParentBackground = False
        TabOrder = 0
        object Splitter1: TSplitter
          Left = 235
          Top = 0
          Width = 5
          Height = 174
          Color = clActiveCaption
          ParentColor = False
          ExplicitLeft = 481
          ExplicitTop = 17
          ExplicitHeight = 431
        end
        object Panel3: TPanel
          AlignWithMargins = True
          Left = 250
          Top = 10
          Width = 211
          Height = 154
          Margins.Left = 10
          Margins.Top = 10
          Margins.Right = 10
          Margins.Bottom = 10
          Align = alClient
          BevelOuter = bvNone
          Caption = 'Panel2'
          Color = clWhite
          ParentBackground = False
          TabOrder = 0
          ExplicitLeft = 451
          ExplicitTop = 5
          ExplicitWidth = 452
          ExplicitHeight = 425
        end
        object Panel4: TPanel
          AlignWithMargins = True
          Left = 10
          Top = 10
          Width = 215
          Height = 154
          Margins.Left = 10
          Margins.Top = 10
          Margins.Right = 10
          Margins.Bottom = 10
          Align = alLeft
          BevelOuter = bvNone
          Caption = 'Panel1'
          Color = clWhite
          ParentBackground = False
          TabOrder = 1
          ExplicitHeight = 210
        end
      end
      object Panel2: TPanel
        AlignWithMargins = True
        Left = 3
        Top = 186
        Width = 471
        Height = 171
        Align = alClient
        BevelOuter = bvNone
        ParentBackground = False
        TabOrder = 1
        ExplicitLeft = 168
        ExplicitTop = 344
        ExplicitWidth = 185
        ExplicitHeight = 41
        object Splitter2: TSplitter
          Left = 235
          Top = 0
          Width = 5
          Height = 171
          Color = clActiveCaption
          ParentColor = False
          ExplicitLeft = 448
          ExplicitTop = 2
          ExplicitHeight = 425
        end
        object Panel5: TPanel
          AlignWithMargins = True
          Left = 10
          Top = 10
          Width = 215
          Height = 151
          Margins.Left = 10
          Margins.Top = 10
          Margins.Right = 10
          Margins.Bottom = 10
          Align = alLeft
          BevelOuter = bvNone
          Caption = 'Panel3'
          Color = clWhite
          ParentBackground = False
          TabOrder = 0
          ExplicitHeight = 95
        end
        object Panel6: TPanel
          AlignWithMargins = True
          Left = 250
          Top = 10
          Width = 211
          Height = 151
          Margins.Left = 10
          Margins.Top = 10
          Margins.Right = 10
          Margins.Bottom = 10
          Align = alClient
          BevelOuter = bvNone
          Caption = 'Panel4'
          Color = clWhite
          ParentBackground = False
          TabOrder = 1
          ExplicitLeft = 451
          ExplicitTop = 5
          ExplicitWidth = 1027
          ExplicitHeight = 425
        end
      end
    end

     


  5. I noticed a difference how code completion shows types in some cases. Here I have example of difference between types for variables and arguments:

     

    image.thumb.png.0ea11a007ace8368eb8f22630c6c5806.png

     

    image.thumb.png.1d814e8a1b812ffc6e3097f6e2730b69.png

     

    image.thumb.png.7d6cc4ed69fc58250a77623fef091f6d.png

     

    Especially for TLst to shows as class(class(TObject) is quite different than TList<integer>.

     

    In some of my code, that I can't replicate, the type for TArray<TRec> is shown as array of TRec. Not a big deal, I guess. 

     

    I would expect in D11 that TArray and TList would resolve correctly, as defined. 

     

     

    Or is this behavior correct and code completion works as expected, I just don't have the knowledge to understand it?

     

     

    Test code:

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils, System.Generics.Collections;
    
    type
      TRec = record
      end;
      TArr = TArray<TRec>;
      TArrInt = TArray<integer>;
      TLst = TList<TRec>;
      TLstInt = TList<integer>;
    
    procedure Test(arr: TArr; lst: TLst);
    begin
    end;
    
    var
        xArr: TArr;
        xArrInt: TArrInt;
        xLst: TLst;
        xLstInt: TLstInt;
    
    begin
      //Test(
    end.

     


  6. Thanks, I do have correct version as you pointed out, but this was a test if it works. casting with AS  fails, but this one worked and just wanted to try to figure out why. 

     

    Was testing what is good general option for lists and with TStrings works pretty well:

     

    procedure TForm1.FormCreate(Sender: TObject);
    var vStrings: TStringList;
    begin
      vStrings := TStringList.Create;
      try
        if FillStrings(vStrings) then
          Label1.Caption := vStrings.DelimitedText;
      finally
        vStrings.Free;
      end;
    
      FillStrings(Memo1.Lines);
      FillStrings(ListBox1.Items);
    end;

     

    Then I set a test with TStringList as parameter and of course Memo and ListBox were failing.

     

     

     

    2 hours ago, Remy Lebeau said:

    vtable contents

    Thanks, I didn't know how this info is called.

     

    Perhaps it would be useful if IDE had optional debug window with VTM data, like CPU window. (Reading this I assume it's possible https://hallvards.blogspot.com/2006/03/hack-8-explicit-vmt-calls.html


  7. I'm not sure how to even ask this, so let me try explain:

     

    I noticed that even if you cast variable as parameter, it works - the value is returned (I was sure casting will just pass a value):

     

    function FillStrings(aStrings: TStringList): boolean;
    begin
      aStrings.Add('a');
      aStrings.Add('b');
    end;
    ...
    
    FillStrings(TStringlist(Memo1.Lines));

    This works, and this doesn't:

     

    FillStrings(Memo1.Lines);

     

    So I was trying to see if CPU debug window will show anything how the Lines were casted. Of course not.

     

    So, is it possible to see how compiler saves info about the parameters, to see what information it has on parameter when casting and when not?


  8. On 2/13/2022 at 8:34 AM, dados said:

    It seems that running SynEdit in debug mode has a huge affect on performance. Running a release is still fast 🙂

    Thank for pointing this out! I was looking into why so sluggish on my text files (108 MB file size, 1Mio lines), but in release mode is still pretty fast. 🙂 


  9. 35 minutes ago, dummzeuch said:

    The 13th (or even 14th in banks) monthly salary in Germany is no bonus, It is part of the regular salary and cannot be withheld if business is slow. It is usually paid with the November salary.

     

    It is kind of a tradition here. Personally I think that is kind of stupid. There isn't really any advantage in getting paid the yearly salary in 13 parts rather than 12, but apparently many people don't understand that and insist on it.

     

    Of course there are also contracts which specifically specify as a bonus (sometimes on top of the 13 monthly salaries), which in that case isn't considered a "13th monthly salary" but (guess what?) a bonus.

    Interesting. I know for a few eastern European countries do have these 13th+ salaries as bonuses, if company does well. I guess the more west you go, the less bonus is really a bonus. I know UK doesn't have 13th month pay.

     


  10. On 6/22/2022 at 2:49 PM, Darian Miller said:

    In the U.S. you should be getting at least $100k as a Delphi developer with more than two years experience.  $120k should be negotiated for an experienced Delphi developer (although I have recently seen people trying to get away with hiring Delphi devs at $60k in the U.S. which is why they cannot find anyone to fill the positions.)

    That's very common in US, it's a big country and you can't expect Silicon Valley to have same salaries as some other states. And in this Covid era, I see $60K to be acceptable offer for beginners positions, or a part-time job, if full remote.

     

    On 6/23/2022 at 5:26 AM, PaPaNi said:

    in Germany "13" salary is often paid. The question is whether this was properly taken into account. Only 12 months are used in the methodology.

    Unlikely the bonuses are included in reported as a yearly salary, since it varies from year to year and also usually you don't know you get it until you actually do. I'm sure you probably know Austria has quite common the 13th and 14th month bonus (and 15th! in rare cases).

    Such bonuses are quite common in European companies doing well. In US, when companies are doing well, you get free coffee and donuts and team building days.

     

     

    A 35% increase in salary in 1 year... yeah right 🙂

    image.thumb.png.721afc00461aa531489b27789c4d74ee.png

     

     


  11. On 5/19/2022 at 5:45 AM, Martin Sedgewick said:

    F2084 Internal Error - I forgot about that one as I have not seen that in a while now! Thankfully 🙂

    I noticed this error most of the time in only 1 unit and I finally was able to refactor it (it was using a lot of other units). No more of this error since then! 🙂 

  12. date


    I have a few overloads for YY conversion, mostly used to convert from imported text files:

     

    function GetYYFromDate(const aDate: TDate): integer; overload;
    begin
      // 01/01/2019 -> 19
      Result := FormatDateTime('yy', aDate).ToInteger;
    end;
    
    function GetYYFromDate(const aDate: TDateTime): integer; overload;
    begin
      // 01/01/2019 01:01:01 -> 19
      Result := FormatDateTime('yy', aDate).ToInteger;
    end;
    
    function GetYYFromDate(const aDate: string): integer; overload;
    begin
      // '01/01/2019' -> 19
      Result := Copy(aDate, Length(aDate) - 2, Length(aDate)).ToInteger;
    end;
    
    function GetYYFromYear(const aYear: string): integer; overload;
    begin
      // '2019' -> 19
      Result := Copy(aYear, Length(aYear) - 2, Length(aYear)).ToInteger;
    end;
    
    function GetYYFromYear(const aYear: integer): integer; overload;
    begin
      // 2019 -> 19
      Result := aYear mod 100;
    end;

     

    • Like 1

  13. Each TabSheet has a TabVisible property, if you set it to False it will hide that tab. To hide/show a TabSheet there is Visible property.

     

    I see that linked documentation in 1 post up is working now. Still wanted to point out the 2 similarly named properties, they could choose better naming.

    • Like 1

  14. 2 minutes ago, Uwe Raabe said:

    DPI unaware mode doesn't hinder you to write DPI aware applications with Delphi, which works pretty well meanwhile. It is just that the IDE runs at 96 dpi internally scaled by Windows.

    I didn't know this. I see that they did improve High DPI in 11 (https://blogs.embarcadero.com/new-in-rad-studio-11-high-dpi-ide-and-form-designing/) I will have to re-check. Last time I ran my projects on 4K monitor and various scalings, it looked good, not perfect, but usable.

     


  15. 23 hours ago, Martin Sedgewick said:

    Would be great to see a roadmap too. No idea what is happening next!

    I lowered my expectations what they can/will deliver, so I think that's why I'm surprised of the D11.1 quality.

     

     

    3 hours ago, emileverh said:

    'High DPI unaware' mode. There are for me still too many issues with High DPI

    So far, I'm not touching any High DPI stuff, yet. But I would probably get to the same conclusion as you, not mature enough yet.


  16.  

    On 5/17/2022 at 2:35 PM, PawelPepe said:

    Ps: If this is to difficult/complex - how much many would it cost for you to write some simple solution for me?

    If you search this forum, you will see this kind of questions never get any answer here, but you will probably get a response within minutes if you post this as project on freelancer and set your minimum budget.


  17. 1 more observation: in 10.2, when ctrl+click worked, it worked even if code in other part of the project didn't compile. 11.1 needs compiler to not fail and ctrl+click works.

    Example: working on UnitA and try to compile and it fails.. perhaps a type is missing or used incorrectly. Open UnitB and check some info, use ctrl+click to jump around. In 10.2 the ctrl+click will work in UnitB. In 11.1 the Ctrl+click will not work anywhere, it stops working for the whole project, because the last compile failed. It starts working as soon as compile is successful.

     


  18. Pretty impressed by Delphi 11.1!
    Upgraded most of my projects from 10.2 and finally I can say that this is version stable enough to move from 10.2. Versions 10.3 and 10.4 were just not ready.

     

    A few observations:
    - IDE crashes a lot less (perhaps only 2 crash & close so far)
    - still occasional F2084 Internal Error, but at least it doesn't close IDE and you can just compile again (10.2 would crash and close most of the time on these errors)
    - The LSP works pretty good, there's constant delay, but is worth waiting because it works correctly most of the time

    - I was hoping the IDE would be slightly faster, but there is a constant slight delay (I assume LSP is kicking in)

    - ctlr+click works better, almost always
    - faster handling big main form (open, close)

    - commenting lines works without a glitch (10.2: sometimes when I want to comment a line, as soon as I press CTRL+/ the cursor jumps up and down and it comments the first line in the unit. very annoying)

    - 64bit compiler compiles faster and always (10.2 would crash often)
    - error insight is improved and more accurate
    - Structure view improved, faster and less jittery (10.2 would occasionally hang for a bit on large form)
    - compiler hints improved, more are shown right from the start so you can sort them out (10.2 would suddenly surprise you with a few more that were not shown before)
    - I like the new Options window, the size persists, especially Library window

    - context option to close units: Close - All to the right, is pretty nice, too!

     

    They did break one thing (well, it was broken in 10.3 already, still not fixed), but is not a deal breaker (at this point):
    - Debug Watch list evaluator is broken for some simple cases ( https://en.delphipraxis.net/topic/6751-simple-debugger-bug-in-111/ )

     

    Embarcadero did a good job with D11.1!

     

     

    • Like 6

  19. 12 minutes ago, Stefan Glienke said:

    MidStr has nothing to do with it - it's a bug in the evaluator. If you put MidStr(vLine, 6, 1) into the evaluator it properly shows 'n'.

    Please report

    OK, it makes sense. Well, at least the workaround is simple: don't give debugger any tough math to do.

    • Haha 1
×