Msg.Result := HTBOTTOMRIGHT
else Msg.Result := HTRIGHT
else
if Pt.Y < BorderMouseSensivity then
if Pt.X < CornerMouseSensivity then Msg.Result := HTTOPLEFT
else
if Pt.X >= PanelHole.Width - CornerMouseSensivity then
Msg.Result := HTTOPRIGHT
else Msg.Result := HTTOP
else
if Pt.Y >= PanelHole.Height - BorderMouseSensivity then
if Pt.X < CornerMouseSensivity then
Msg.Result := HTBOTTOMLEFT
else
if Pt.X >= PanelHole.Width - CornerMouseSensivity then
Msg.Result := HTBOTTOMRIGHT
else Msg. Result := HTBOTTOM;
end
else if Msg.Msg = WM_SIZE then
begin
// Пересчитываем регион SetRegion;
// Устанавливаем новые ограничения для размеров окна.
// учитывающие новое положение дырки
Constraints.MinWidth :=
Width - ClientWidth + PanelHole.Left + MinHoleSize + HoleDistance;
Constraints.MinHeight :=
Height - ClientHeight + PanelHole.Top + MinHoleSize + HoleDistance;
end
else if Msg.Msg = WM_SIZING then
begin
// Копируем переданный прямоугольник в переменную R,
// одновременно пересчитывая координаты из экранных
// в клиентские
R.TopLeft := ScreenToClient(PRect(Msg.LParam)^.TopLeft);
R.BottomRight := ScreenToClient(PRect(Msg.LParam)^.BottomRight);
// Если ширина слишком мала, проверяем, за какую
// сторону тянет пользователь. Если за левую -
// корректируем координаты левой стороны, если за
// правую - ее координаты
if R.Right - R.Left < MinHoleSize then
if Msg.WParam in [WMSZ_BOTTOMLEFT, WMSZ_LEFT, WMSZ_TOPLEFT] then
R.Left := R.Right - MinHoleSize
else
R.Right := R.Left + MinHoleSize;
// Аналогично действуем, если слишком мала высота
if R.Bottom - R.Top < MinHoleSize then
if Msg.WParam in [WMSZ_TOP, WMSZ_TOPLEFT, WMSZ_TOPRIGHT] then
R.Top := R.Bottom - MinHoleSize
else R.Bottom := R.Top + MinHoleSize;
// Сдвигаем стороны, слишком близко подошедшие
// к границам окна
if R.Left < HoleDistance then R.Left := HoleDistance;
if R.Top < HoleDistance then R.Top := HoleDistance;
if R.Right > ClientWidth - HoleDistance then
R.Right := ClientWidth - HoleDistance;
if R.Bottom > ClientHeight - HoleDistance then
R.Bottom := ClientHeight - HoleDistance;
// Копируем прямоугольник R, переводя его координаты
// обратно в экранные
PRect(Msg.LParam)^.TopLeft := ClientToScreen(R.TopLeft);
PRect(Msg.LParam)^.BottomRight := ClientToScreen(R.BottomRight);
end;
end;
Остается еще одна ситуация, когда границы "дырки" могут подойти к границам окна слишком близко: когда пользователь меняет не границы "дырки", а границы самого окна. Чтобы этого не случилось, нужно отслеживать изменения размеров окна и соответствующим образом менять размеры дырки — для этого нам потребуется изменить размеры панели и пересчитать регион. Пересчет региона необходим и в случае увеличения размеров окна: если его не пересчитать, получится, что часть окна не будет попадать в регион и будет отрезана. Все перечисленные действия выполняются в обработчике сообщения WM_SIZE
окна (листинг 1.54).
Листинг 1.54. Обработчик сообщения WM_SIZE
главного окна
procedure TFormHole.WMSize(var Msg: TWMSize);
begin
inherited;
// При уменьшении размеров окна уменьшаем размер дырки,
// если границы окна подошли слишком близко к ней
if PanelHole.Left + PanelHole.Width > ClientWidth - HoleDistance then
PanelHole.Width := ClientWidth - HoleDistance - PanelHole.Left;
if PanelHole.Top + PanelHole.Height > ClientHeight - HoleDistance then
PanelHole.Height := ClientHeight - HoleDistance - PanelHole.Top;
// На случай увеличения окна пересчитываем его регион,
// иначе та часть, которая добавилась, окажется за его
// пределами и будет отрезана SetRegion;
// Пересчитываем координаты стрелок
CalculateArrows;
Invalidate;
end;
Напоследок добавим к программе один "бантик": красные стрелки по углам формы, за которые можно потянуть, чтобы изменить ее размер. Каждая стрелка будет представляться отдельным регионом. Координаты регионов должны быть привязаны к соответствующим углам окна, поэтому при изменении размеров окна эти координаты придется пересчитывать (в листинге 1.54 можно найти соответствующий вызов). Все стрелки выглядят одинаково, но являются зеркальным отражением друг друга. Чтобы рассчитывать координаты стрелок, мы зададим координаты одной нарисованной заранее стрелки в виде константы, а потом будем рассчитывать на основе этих данных координаты реальных стрелок, отражая их от нужной плоскости и добавляя требуемое смещение (листинг 1.55).
Листинг 1.55. Расчет координат стрелок
// координаты верхней левой стрелки, отсчитанные от точки
// (0,0). Для получения координат реальных стрелок эти точки
Читать дальше
Конец ознакомительного отрывка
Купить книгу