How to set only 1 specific sizing border edge?

612 views Asked by At

I have some tool-panels made via forms with bsSizeToolWin borders, i have custom handling of window-movement and custom routines for sticking/aligning tool-panels with borders of main form (almost like docking functionality), but the problem that with bsSizeToolWin border-style i have all the corners/sides of border sizeable.

Is it possible to make only one specific border-side sizeable? (e.g. when tool-panel sticked to left border of main form i want only right border of panel sizeable, cuz top and bottom coords of panel getting aligned according to height of client area of main form and left coord sticked to right border of main form)

1

There are 1 answers

5
Remy Lebeau On BEST ANSWER

From a visual standpoint, by default if a window has sizable borders then all edges are drawn sizable, otherwise none of them are, there is no in-between as the Win32 API has no concept of per-edge border styles, only whole-window border styles. If you want the various borders to look different, you would likely have to custom-draw the borders manually by handling the WM_NCCALCSIZE and WM_NCPAINT messages directly.

From a functional standpoint, it is fairly easy to prevent the user from resizing the window on specific edges. The simplest way is to have the panel handle the WM_NCHITTEST message. Give the panel normal sizing borders (custom drawn if desired), and then have it pass any received WM_NCHITTEST message to the default handler first, and then adjust the result as needed. The benefit of this approach is that the OS will not allow the user to grab any edge that is reported as HTBORDER (non-sizable border), and there will be no visual feedback that the edge is resizable (even if it really is).

For instance, let's use your panel-aligned-on-the-left example. If the default handler returns either HTBOTTOM, HTBOTTOMLEFT, HTLEFT, HTTOPLEFT, or HTTOP, return HTBORDER instead. If the default handler returns HTBOTTOMRIGHT or HTTOPRIGHT, return HTRIGHT instead. Otherwise return whatever the default handler returned.

Adjust the values as needed based on which edge of your Panel you want to be sizable.

For example:

type
  TMyPanelForm = class(TForm)
  private
    fWhichSideCanBeResized: TAlign;
    procedure WMNCHitTest(var Message: TMessage); message WM_NCHITTEST;
  end;

procedure TMyPanelForm.WMNCHitTest(var Message: TMessage);
begin
  inherited;
  case fWhichSideCanBeResized of
    alLeft:
    begin
      case Message.Result of
        HTBOTTOM, HTBOTTOMRIGHT, HTRIGHT, HTTOPRIGHT, HTTOP:
          Message.Result := HTBORDER;
        HTBOTTOMLEFT, HTTOPLEFT:
          Message.Result := HTLEFT;
      end;
    end;
    alRight:
    begin
      case Message.Result of
        HTBOTTOM, HTBOTTOMLEFT, HTLEFT, HTTOPLEFT, HTTOP:
          Message.Result := HTBORDER;
        HTBOTTOMRIGHT, HTTOPRIGHT:
          Message.Result := HTRIGHT;
      end;
    end;
    alTop:
    begin
      case Message.Result of
        HTLEFT, HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT, HTRIGHT:
          Message.Result := HTBORDER;
        HTTOPLEFT, HTTOPRIGHT:
          Message.Result := HTTOP;
      end;
    end;
    alBottom:
    begin
      case Message.Result of
        HTLEFT, HTTOPLEFT, HTTOP, HTTOPRIGHT, HTRIGHT:
          Message.Result := HTBORDER;
        HTBOTTOMLEFT, HTBOTTOMRIGHT:
          Message.Result := HTBOTTOM;
      end;
    end;
  end;
end;

Alternatively:

procedure TMyPanelForm.WMNCHitTest(var Message: TMessage);
begin
  inherited;
  case Message.Result of
    HTLEFT:
      if fWhichSideCanBeResized <> alLeft then
        Message.Result := HTBORDER;
    HTRIGHT:
      if fWhichSideCanBeResized <> alRight then
        Message.Result := HTBORDER;
    HTTOP:
      if fWhichSideCanBeResized <> alTop then
        Message.Result := HTBORDER;
    HTBOTTOM:
      if fWhichSideCanBeResized <> alBottom then
        Message.Result := HTBORDER;
    HTTOPLEFT:
      case fWhichSideCanBeResized of
        alTop: Message.Result := HTTOP;
        alLeft: Message.Result := HTLEFT;
      else
        Message.Result := HTBORDER;
      end;
    HTBOTTOMLEFT:
      case fWhichSideCanBeResized of
        alBottom: Message.Result := HTBOTTOM;
        alLeft: Message.Result := HTLEFT;
      else
        Message.Result := HTBORDER;
      end;
    HTTOPRIGHT:
      case fWhichSideCanBeResized of
        alTop: Message.Result := HTTOP;
        alRight: Message.Result := HTRIGHT;
      else
        Message.Result := HTBORDER;
      end;
    HTBOTTOMRIGHT:
      case fWhichSideCanBeResized of
        alBottom: Message.Result := HTBOTTOM;
        alRight: Message.Result := HTRIGHT;
      else
        Message.Result := HTBORDER;
      end;
  end;
end;