Results 1 to 10 of 10

Thread: "Snapped" form resize like in Delphi 7 Object Inspector

  1. #1

    "Snapped" form resize like in Delphi 7 Object Inspector

    Run D7, dunno if other versions also have this feature. Make sure you have Object Inspector visible.
    Object Inspector is basically grid with specific number of rows.

    You can adjust its width to anything you want.

    But if you adjust the height (resize it to up or down) then you see like snapping to each row or something like that. Dunno how to say it properly.

    The height is adjusted not smoothly but snapping to the height of the rows in Object Inspector grid.


    How could that be done?
    I dont have Lazarus installed atm, maybe it also has this, i could take a look the source but if not how i could do same thing?

    Is the math behind it very difficult?
    I would like to make this feature for both width and height fro my editor tile picker window. I like that "snapping".

    There are few properties for forms like: "FormCanResize" and "FormConstrainedResize".
    Maybe Delphi also uses that. Dunno.

    TIA for any tip.
    Last edited by hwnd; 08-09-2013 at 11:22 AM.

  2. #2
    Ok, found a way but after each "snap" it has some offset more and more.
    Make new project, drop a drawgrid to it, set its DefaultRowHeight to 64, DefaultColWidth to 64. No fixedcols or rows.
    Add this to private section of Form1:

    Code:
    procedure WMWindowPosChanging (var Msg: TWMWindowPosMsg); message WM_WINDOWPOSCHANGING;
    And this in implementation:

    Code:
    procedure TForm1.WMWindowPosChanging(var Msg: TWMWindowPosChanging);
    begin
        if (Msg.WindowPos^.flags and SWP_NOSIZE = 0) and ((Msg.WindowPos^.cx <> Width)
            or (Msg.WindowPos^.cy <> Height))
      then
            begin
              Msg.WindowPos^.cx:=(Msg.WindowPos^.cx div 70)*70;
          Msg.WindowPos^.cy:=(Msg.WindowPos^.cy div 70)*70;
            end;
    end;
    Resize the form..

    The less columns or rows then the bigger offset gets.
    Maybe scollbars and grid line width is making troubles here, dunno.

    Any ideas?

    EDIT: Found another solution:
    https://groups.google.com/forum/#!to...pi/39tMGvqXjog

    I used ValueListEditor and if i set the INC_SIZE to DefaultRowHeight of the ValueListEditor, then there is no offset problem.
    But it still shows the small portion of item below the current last visible row.
    If i change the INC_SIZE to smaller or bigger i get the offset bug right away after resizing.
    Last edited by hwnd; 08-09-2013 at 01:10 PM.

  3. #3
    WOW!
    When I look at the code examples you tried all of them seem much more complicated that one I will present you.

    So here is my example which is much easier and works perfectly. It uses Forms OnCanResize notification event.
    Code:
    procedure TForm3.FormCanResize(Sender: TObject; var NewWidth,
      NewHeight: Integer; var Resize: Boolean);
    var HorizontalBorderWidth: Integer;
        VerticalBorderWidth: Integer;
        X,Y: Integer;
          //Constants defining row anbd column dimensions
    const ColumnWidth = 20;
          RowHeight = 20;
    begin
        //Calculate number of pixels used for left and right Form border
        //We use this to calculate needed horizontal Form size to get certain Form ClientWidth
        HorizontalBorderWidth := Width - ClientWidth;
        NewWidth := ((NewWidth div ColumnWidth) * ColumnWidth) + HorizontalBorderWidth;
        //Calculate number of pixels used for top and bottom Form border
        //We use this to calculate needed vertivcal Form size to get certain Form ClientHeight
        VerticalBorderHeight := Height - ClientHeight;
        NewHeight := ((NewHeight div RowHeight) * RowHeight) + VerticalBorderHeight;
        //Draw a rid for easier referencing of Form size
        for X := 0 to 100 do
        begin
            Form3.Canvas.MoveTo(X*ColumnWidth,0);
            Form3.Canvas.LineTo(X*ColumnWidth,2000);
        end;
        for Y := 0 to 100 do
        begin
            Form3.Canvas.MoveTo(0,Y*RowHeight);
            Form3.Canvas.LineTo(2000,Y*RowHeight);
        end;
    end;
    If you want your Form to be resized in a way so that some Panel on your Form would have suitable size for showing only whole rows and columns you only need to change the way how HorizontalBorderWidth and VerticalBorderHeight are calculated.
    Code:
    HorizontalBorderWidth := Width - Panel.ClientWidth;
    VerticalBorderHeight := Height - Panel.ClientHeight;
    This code should probably work in any version of Delphi and Lazarus.

  4. #4
    Thanks you for this!
    You forgot to declare VerticalBorderHeight.

    But why the bottom part flickers so much? The right side seems ok, but bottom part is flickering.
    The form wants to resize but it cant and flickers.

    Even if i set doublebuffered to true and comment out the grid drawing.

    EDIT
    I downloaded some old free open source Delphi Object Inspector "clone" for Delphi 3 and it had the snapping in it.

    Drop a DrawGrid on form, set fixedcols,fixedrows to 0, defaultcolwidth to 64, defaultrowheight to 64. Thats the tilesize i use.
    And set Align of DrawGrid1 to alClient.

    Code:
    // Add this to private section of Form1
    Procedure WhileSizing(Var msg : tmessage);  Message WM_SIZING;
    
    
    procedure TForm1.WhileSizing(var msg: tmessage);
    
    var PR : PRect;                              { Makes it so there's never half }
         Offset, offset2 : Integer;                        { a row showing in the listbox. }
         Growing : Boolean;
         Top, left : Boolean;
         Lb :tdrawgrid;
    Begin
     Lb := DrawGrid1;
      if not (msg.wparam in [wmsz_top, wmsz_topleft, wmsz_topright,
                             wmsz_bottom, wmsz_bottomleft, wmsz_bottomright]) then exit;
      pr := Pointer(msg.Lparam);
      if (pr.bottom - pr.top) = height then exit;
      msg.result:= 1;
    
      OffSet := ((pr.bottom - pr.top) - (height - Lb.clientheight)) mod lb.DefaultRowHeight;
      Growing := (pr.bottom - pr.top) > height;
      top := msg.wparam in [wmsz_top, wmsz_topleft, wmsz_topright];
      //left := msg.WParam in [wmsz_bottom, wmsz_bottomleft, wmsz_bottomright ];
    
      if top then Begin
        if growing then
          pr.top := pr.top + offset
        else
          pr.top := pr.top - (lb.DefaultRowHeight  - offset);
      End Else Begin
        if Growing then
          pr.bottom := pr.Bottom - offset
        else
          pr.bottom := pr.bottom + (lb.DefaultRowHeight  - offset);
      End;
    
    end;
    It works the way i need, but i must make this work for right side also.
    If anybody would like to help with this, then please.

    Atm im watching and reading that code, because i dont understand everything in it.
    If i would know i would convert it by myself.

    I probably have to take piece of paper and pencil and calculate everything on that until i get it. Then i should be able to convert it to left and right side resizing.
    Last edited by hwnd; 08-09-2013 at 09:42 PM.

  5. #5
    Quote Originally Posted by hwnd View Post
    You forgot to declare VerticalBorderHeight.
    Actually I just forget to change VerticalBorderWidth to VerticalBorderHeight in variable declaration.
    This can happen when you are corceting the spelling mistakes on forum and not in Delphi


    Quote Originally Posted by hwnd View Post
    But why the bottom part flickers so much? The right side seems ok, but bottom part is flickering.
    The form wants to resize but it cant and flickers.
    That is strange. I havent encountered any flickering when testing.
    Are you maybe handling Windows messages as showed in other examples at the same time? That could be the cause. I can't think of any other reason for flickering.

  6. #6
    Oh, sorry, forgot to update the ColumnWidth and ColumnHeight variables. One had 64 and another 20.
    I will try the drawgrid now.
    Like in example above, i dont want half rows or half columns, only full rows and full columns.


    i will try to make it.
    If i cant,i will let you know.
    EDIT: your grid itself works fine. it has 64x64 cells and form snaps to them.

    Dunno how the drawgrid thingy will work.
    Last edited by hwnd; 08-09-2013 at 10:34 PM.

  7. #7
    It should work OK.
    You might only need to figure out the size of the DrawGrid component border.

  8. #8
    Everything looks almost perfect, now i need a bit help with some math.
    I have 992 tiles, tiles are all 64x64 pixels, and lets say i have grid on form which has 12 columns and 8 rows visible.

    12 * 8 = 96 tiles are currently visible.

    How can i calculate how many columns (and rows) are needed for the rest of the tiles?
    I mean calculate the needed rows / columns for all of the tiles by also counting in current col- and rowcount?

    Whats the proper math?

    I tried something like:
    Code:
    kgrid1.ColCount:=992 div kgrid1.rowCount;
    But it doesnt work very well. Last tiles are not drawn sometimes and sometimes they are.

    Column count can change and same with row count. Because user can resize grid (actually the form).


    Thanks for any tip.

  9. #9
    I don't understand why you need to count that in the first place. When you have a tilemap, you should already know how many rows and columns it has. I'll take a guess it's 31x32 because that makes 992 And yes, 992 div 31 = 32, or 992 div 32 = 31, working in both ways. The problem with rendering does certainly not come down to this math, but other code error.

  10. #10
    Thanks. You are right.

    I just had to initialize colcount / rowcount.

    And remove that, because its useless now:

    kgrid1.ColCount:=992 div kgrid1.rowCount

    It works fine. I still have few things to make, but its too late atm, gtg to sleep.
    And yesterday i also added a "nice feature" that moves scrollbars away from tiles.
    Otherwise the grid scrollbars would hide some of the tiles. But i just made the form bigger, by getting scrollbar width/height from windows and passing it to my code.
    I later will show it.

    Btw just one more question:
    I have currently dynamic 2D array, called tilesheet of integers, i set its length according to numcols and numrows. And then i do:
    Code:
    KGrid1.CellPainter.Canvas.Draw(R.Left, R.Top, sty.getTile( TileSheet[ARow , ACol ]));
    sty.getTile just waits for the tile_id (integer).

    Is it possible to draw all these tiles (992) without that "tilesheet" array?
    Last edited by hwnd; 14-09-2013 at 12:57 AM.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •