Is there a AUI pane move (or dock) event in wxPHP?

2019-07-01 18:54发布

问题:

On this question I have been attempting to capture a AUI pane configuration so that it can be restored if any panes have been closed. The docs are somewhat limited for wxPHP, and upstream for wxWidgets, so I am largely feeling my way around.

I have realised that SavePaneInfo will help me capture the state of a pane - it outputs a perspective string that represents the position and options for a pane at a given moment. All I need to do therefore is to capture when the pane changes and update my internal representation of it.

For the sake of interest, a perspective looks like this:

name=auiPane3;caption=Caption 3;state=2099196;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=90;besth=25;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1

However, capturing a move/dock event is not proving to be trivial. I can see six events connected with AUI:

wxEVT_AUI_FIND_MANAGER
wxEVT_AUI_PANE_BUTTON
wxEVT_AUI_PANE_CLOSE
wxEVT_AUI_PANE_MAXIMISE
wxEVT_AUI_PANE_RESTORE
wxEVT_AUI_PANE_RENDER

I have been able to capture the restore and close events, and the find_manager doesn't seem to do anything. I've tried wxEVT_ANY on this window, which also does not seem to capture anything. I've also tried it on individual panes too, to no avail (nothing is called as far as I can tell):

$managedWindow->getWindowByIndex(0)->Connect(wxEVT_ANY, array($this, "onAny"));

The docs for the upstream library wxWidgets mention this event:

EVT_AUI_PANE_ACTIVATED

However that does not seem to be implemented in wxPHP - is that what I want? It does not quite sound right, but if I can access it without the constant I would certainly try it.

I guess I could use wxAuiManager::SetArtProvider with the standard art provider object, modified to capture pane state, but that feels like a sledgehammer to crack a nut. I could also capture the close event and change the perspective string returned so the 'closed' bit is not set, but that too is not particularly elegant.

What I want to do feels really trivial, and would be in keeping with other parts of wxWidgets, but it is not so. Any suggestions for things to try?

回答1:

I have a solution. I would have liked to detect from the wxAuiManagerEvent which pane is closing, so that I just record the perspective string of a pane as it closes. However this does not seem to be possible:

  • The reference from $event->GetEventObject() is NULL - that may be a wxPHP bug;
  • The pane returned by $event->GetPane() does not have a property or method to read the name of the pane.

I have therefore taken the approach of saving all perspective strings whenever one pane is closed.

I discovered that perspective strings contain a bit to represent the closed status of a pane, so when storing these strings I make sure this bit is unset. Reassembling perspective strings is not the most elegant thing, but it works, and is much better than undocking and redocking (see the linked question in the original post).

Here is some code that loops through my panes, gets the perspective string, unsets the closed flag and saves the perspective in a window list:

public function onPaneClose(wxAuiManagerEvent $event)
{
    for($i = 0; $i <= 7; $i++)
    {
        $pi = $this->getPaneInfoByIndex($i);
        $persp = $this->getManagedWindow()->getAuiManager()->SavePaneInfo($pi);

        // Split perspective string into pieces, get the second one (state)
        $items = explode(';', $persp);
        $state = $items[2];

        // Decode the bitfield within
        $stateItems = explode('=', $state);
        $stateBitfield = (int) $stateItems[1];

        // Set up bitmask to ignore closed state
        $bitMask = (-1 ^ 2);

        // Reset the perspective string minus the closed state bit
        $replacementBitfield = $stateBitfield & $bitMask;
        $items[2] = "state=" . $replacementBitfield;
        $newPersp = implode(';', $items);

        // Finally save the perspective
        $this->windowSaves[$i] = $newPersp;
    }
}


回答2:

I've found another solution, which I think I moderately prefer. It turns out it is possible to get the pane name from the wxAuiPaneInfo object - the perspective contains it! This allows me to simplify the algorithm - I just convert the name to an ordinal, and then save pane perspectives individually.

Since pane close events are always triggered before the close (i.e. when they are still vetoable) they will not have the close bit set, and so happily I do not have to modify that. Here's my new event handler:

public function onPaneClose(wxAuiManagerEvent $event)
{
    // In the absence of being able to read the pane name from a paneinfo
    // method, we can parse it out from the perpective string
    $info = $event->GetPane();
    $persp = $this->getManagedWindow()->getAuiManager()->SavePaneInfo($info);

    // Fish out the number, which represents the pane ordinal
    $matches = [];
    preg_match('#name=auiPane(\d+)#', $persp, $matches);
    if ($matches)
    {
        $index = $matches[1];
        $this->windowSaves[$index] = $persp;
    }
}

I've just used a regex on the perspective string that matches my naming format of auiPane<index>.