2025-11-25 07:01 PM - edited 2025-11-26 12:08 AM
Is there a reliable way to detect when a custom modeless palette (derived from DG::Palette and DG::PanelObserver) changes between docked and undocked states?
I have tried experimenting with different (combinations of) event handlers provided by the DG::PanelObserver base class, but so far I have not been able to design a bulletproof mechanism. Has anyone found a reliable way to hook into the docking/undocking transition, or a recommended pattern for detecting when the palette's IsDocked () state actually changes?
In addition to detecting dock/undock transitions, I would also be interested in a reliable way to detect orientation changes of a docked palette (e.g., switching between horizontal and vertical docking).
The available virtual callbacks provided by the observer class are listed below:
void PanelClosed (const PanelCloseEvent& ev);
void PanelCloseRequested (const PanelCloseRequestEvent& ev, bool* accepted);
void PanelContextHelpRequested (const PanelHelpEvent& ev, GS::UniString* contextHelpAnchor);
void PanelContextMenuRequested (const PanelContextMenuEvent& ev, bool* needHelp, bool* processed);
void PanelDragEntered (const PanelDropTargetEvent& ev, DragDrop::Effect* effect, bool* handleEvent);
void PanelDragEntered (const PanelDropTargetEvent& ev, DragDrop::Effect* effect, bool* handleEvent, bool* rightDragMenu);
void PanelDragMoved (const PanelDropTargetEvent& ev, DragDrop::Effect* effect, bool* handleEvent);
void PanelDragLeft (const PanelDropTargetEvent& ev, bool* handleEvent);
void PanelDropped (const PanelDropTargetEvent& ev, DragDrop::Effect* effect, bool* handleEvent);
void PanelHotkeyPressed (const PanelHotKeyEvent& ev, bool* processed);
void PanelIdle (const PanelIdleEvent& ev);
void PanelOpened (const PanelOpenEvent& ev);
void PanelResizeEntered (const PanelResizeEvent& ev);
void PanelResizing (const PanelResizeEvent& ev, Point* growValues);
void PanelResized (const PanelResizeEvent& ev);
void PanelResizeExited (const PanelResizeEvent& ev);
void PanelMoveEntered (const PanelMoveEvent& ev);
void PanelMoving (const PanelMoveEvent& ev);
void PanelMoved (const PanelMoveEvent& ev);
void PanelMoveExited (const PanelMoveEvent& ev);
void PanelScaleChanged (const PanelScaleChangeEvent& ev);
void PanelToolTipRequested (const PanelHelpEvent& ev, GS::UniString* toolTipText);
void PanelTopStatusGained (const PanelTopStatusEvent& ev);
void PanelTopStatusLost (const PanelTopStatusEvent& ev);
void PanelWheelTrackEntered (const PanelWheelEvent& ev, bool* processed);
void PanelWheelTracked (const PanelWheelTrackEvent& ev, bool* processed);
void PanelWheelTrackExited (const PanelWheelEvent& ev, bool* processed);
void PanelBackgroundPaint (const PanelBackgroundPaintEvent& ev, bool* processed);
void PanelBackgroundPostPaint (const PanelBackgroundPaintEvent& ev);
void PanelActivated (const PanelActivateEvent& ev);
void PanelChangeRegistrationRequested (const Item* item, bool* allowRegistration);
Solved! Go to Solution.
2025-11-26 12:37 PM
Unfortunately there is no dedidated notification or API function to get the info about the docking orientation change of palettes.
However I found that the PanelMoved notification is always sent when the palette is docked or undocked. I think this can be used to detect dock state change.
The dock position can be determined by a bit workier way by comparing the palette rect against the work area rect (the work area rect is the region that a maximized state modeless window occupies). For example a if palette is docked on the left side, then both the left and right edge coordinates of the palette will be smaller (or equal) to the left coordinate of the work area.
The coordinates of the work area can be retrieved by the
DG::FrameWindow::GetWorkAreaRect (false);
function. This will retrieve a NativeRect object using coortinates in pixel units and with origin of the main screen.
The palette rectangle can be retrieved with the same units and origin by the
DG::Dialog::GetFrameRect (void);
function.
I hope these will help to solve this problem.
2025-11-26 12:37 PM
Unfortunately there is no dedidated notification or API function to get the info about the docking orientation change of palettes.
However I found that the PanelMoved notification is always sent when the palette is docked or undocked. I think this can be used to detect dock state change.
The dock position can be determined by a bit workier way by comparing the palette rect against the work area rect (the work area rect is the region that a maximized state modeless window occupies). For example a if palette is docked on the left side, then both the left and right edge coordinates of the palette will be smaller (or equal) to the left coordinate of the work area.
The coordinates of the work area can be retrieved by the
DG::FrameWindow::GetWorkAreaRect (false);
function. This will retrieve a NativeRect object using coortinates in pixel units and with origin of the main screen.
The palette rectangle can be retrieved with the same units and origin by the
DG::Dialog::GetFrameRect (void);
function.
I hope these will help to solve this problem.
2025-11-26 07:31 PM - edited 2025-11-27 06:43 PM
Thank you for your answer, Miklós!
Before posting my question yesterday, I had been thinking along similar lines. However, I was a bit confused about how and in what order the event handlers PanelMoveEntered, PanelMoved, PanelMoveExited, PanelResizedEntered, PanelResized, and PanelResizedExited are actually triggered. During a docking transition, for example, these handlers may be called multiple times until the docking or undocking operation is complete, and while debugging I noticed that their sequence was not always consistent. This made it quite difficult for me to reliably track the events.
In the end, I came up with a solution similar to the one you mentioned: I needed to rely on multiple event handlers, and when switching from one docked orientation to another, I tested the equality of two corner points relative to the reference rectangle. This helped me avoid false signals in cases where a docked palette was simply being resized in its current docked state.
At the moment I am still experimenting with this approach. I would be glad to hear any feedback or suggestions. And of course, thank you — I truly appreciate the time you took to answer my question.
//-------
// header
//-------
class MyPalette final :
public DG::Palette,
public DG::PanelObserver,
public DG::CompoundItemObserver
private:
DG::NativeRect referenceRectangle;
bool wasPreviouslyDocked = false;
bool dockStateOrOrientationHasChanged = false;
// ...
int GetCoincidingCornerCountOfTwoScreenSpaceRectangles (const DG::NativeRect& r1, const DG::NativeRect& r2) const;
void PanelMoved (const DG::PanelMoveEvent& event) override;
void PanelMoveExited (const DG::PanelMoveEvent& event) override;
void PanelResized (const DG::PanelResizeEvent& event) override;
// ...
public:
// constructor
MyPalette ();
// ...
};
//-------
// source
//-------
int MyPalette::GetCoincidingCornerCountOfTwoScreenSpaceRectangles (const DG::NativeRect& r1, const DG::NativeRect& r2) const
{
int count = 0;
if (r1.GetLeftTop () == r2.GetLeftTop ()) ++count;
if (r1.GetRightTop () == r2.GetRightTop ()) ++count;
if (r1.GetLeftBottom () == r2.GetLeftBottom ()) ++count;
if (r1.GetRightBottom () == r2.GetRightBottom ()) ++count;
return count;
}
MyPalette::MyPalette () :
DG::Palette (ACAPI_GetOwnResModule (), ID_ADDON_PALETTE, ACAPI_GetOwnResModule (), paletteGuid),
{
Attach (*this);
AttachToAllItems (*this);
BeginEventProcessing ();
// ...
wasPreviouslyDocked = IsDocked ();
referenceRectangle = GetReferenceRectangleInScreenSpace ();
}
void MyPalette::PanelMoved (const DG::PanelMoveEvent& /*event*/)
{
// note that PanelMove may be called multiple times during docking transitions...
dockStateOrOrientationHasChanged =
(wasPreviouslyDocked != IsDocked () ||
(wasPreviouslyDocked && IsDocked () && CoincidingCornerCountOfTwoScreenSpaceRectangles (referenceRectangle, GetReferenceRectangleInScreenSpace ()) < 2));
}
void MyPalette::PanelMoveExited (const DG::PanelMoveEvent& /*event*/)
{
dockStateOrOrientationHasChanged =
(wasPreviouslyDocked != IsDocked () ||
(wasPreviouslyDocked && IsDocked () && CoincidingCornerCountOfTwoScreenSpaceRectangles (referenceRectangle, GetReferenceRectangleInScreenSpace ()) < 2));
if (dockStateOrOrientationHasChanged) {
PerformDockStateTransitionRelatedOperations ();
}
}
void MyPalette::PanelResized (const DG::PanelResizeEvent& event)
{
const short horizontalChange = event.GetHorizontalChange ();
const short verticalChange = event.GetVerticalChange ();
if (horizontalChange == 0 && verticalChange == 0) {
return;
}
BeginMoveResizeItems ();
// usual resizing/moving operations...
EndMoveResizeItems ();
if (dockStateOrOrientationHasChanged) {
PerformDockStateTransitionRelatedOperations ();
}
}
void MyPalette::PerformDockStateTransitionRelatedOperations ()
{
// do something nice and meaningful
// ...
// then
wasPreviouslyDocked = IsDocked ();
dockStateOrOrientationHasChanged = false;
referenceRectangle = GetReferenceRectangleInScreenSpace ();
}
2025-11-27 03:18 PM
Well, thanks for the feedback!
It is true that some messages are not consistently triggered. 😞 But in your case the PanelMoved might be usable. I found that it was always raised after the palette was docked/undocked. So in the PanelMoved handler the new and previous docking state can be compared to detect a change.