Architecture of switching between page panels

For my Windows activation / registration app, I have around 10 different panels that the user moves through during the process. I figure a PagePanel with ContainerControls probably makes the most sense.

In my working MacOS / Cocoa Objective-C++ version, I have a central NSWindowController that adds/removes NSViewControllers as different pages are required. It also handles transitions between the panels, and resizes the window to accommodate the size of the contained panel.

Is that architecture (or a similar architecture) viable with Xojo? I realize I CAN ask the Window to change the PagePanel without dealing with adding/removing controllers. Note that the choice of the next panel to display is sometimes invoked programmatically (for example, an error might result in displaying an error panel).

Should I create a custom event for changing the panel, so I can invoke that event from any place in my code? If so, would the Window containing the PagePanel service that event?

NOTE: Iā€™m saying ā€œeventā€ because Iā€™m concerned that directly calling my own method to change the panel could result in nesting a lot of code ā€“ eg a request to change panels MIGHT result in another request to change panels. If events are queued, then an event SHOULD provide some isolation from accidental recursion.

I may have misunderstood what you want, as it sounds simpleā€¦

The Pagepanel control will handle all of this for you.
Give it 10 panels, and place on each , the controls you need to display.

All the window has to do is set the ā€˜visible panelā€™
The remainder will be hidden.

In the Layout Editor, you navigate among panels in a Page Panel control using the widget at the bottom of the control

Get or set the SelectedPanelIndex

2 Likes

My app has six or seven panels on the pagepanel. Switching between them is trivial. You donā€™t need to create anything, just set the SelectedPanelIndex, as @Jeff_Tullin says.

Note that the widget for switching panels that he refers to is used only in the IDE when you are designing the setup. It doesnā€™t exist at runtime.

1 Like

@Jeff_Tullin ā€“

All the window has to do is set the ā€˜visible panelā€™

Absolutely, but if I want to invoke a transition from one page panel to another, I probably should do that from a centralized method. (like resizing the enclosing window to match the size of the visible panel)

Thanks ā€“ Iā€™ll give it a try and see if that works as simply as you suggest.

From the docs:

The PanelChanged event handler is called when the SelectedPanelIndex property changes.

Although I have to say that a window which changes size because you switch panels might be a bit unnervingā€¦

1 Like

If each panel may contain data that should be saved when switching to another, then yes, one method to effect that is useful. Seems I call it from 21 places in my app. Looks like I donā€™t use the PanelChanged event handler at all.

Thatā€™s been the interface for MacOS System Preferences for a decade. Also, take a look at the Xojo Options window (Edit > Options) ā€“ although Xojoā€™s Options window only changes HEIGHT, not width, and doesnā€™t animate between heights.

This will animate the window during a resize, on macOS, and just resize the window on Windows and Linux

Protected Sub WindowResizeAnimated(inWindow as DesktopWindow, width as Integer, height as Integer)
  #if TargetCocoa
    // If you copy this method, you will need the following structure: NSRect
    
    Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
    Declare Function NSSelectorFromString Lib "Cocoa" (aSelectorName As CFStringRef) As Ptr
    Declare Function RespondsToSelector Lib "Cocoa" Selector "respondsToSelector:" (NSWindow As Ptr, aSelector As Ptr) As Boolean
    Declare Function Frame Lib "Cocoa" Selector "frame" (NSWindow As Ptr) As NSRect
    Declare Sub SetFrameDisplayAnimate Lib "Cocoa" Selector "setFrame:display:animate:" (NSWindow As Ptr, inNSRect As NSRect, Display As Boolean, Animate As Boolean)
    
    DIM FrameSelector As Ptr = NSSelectorFromString("frame")
    DIM SetFrameDisplayAnimateSelector As Ptr = NSSelectorFromString("setFrame:display:animate:")
    
    if (RespondsToSelector(inWindow.Handle, FrameSelector)) AND (RespondsToSelector(inWindow.Handle, SetFrameDisplayAnimateSelector)) then
      DIM deltaWidth As CGFloat = width - inWindow.Width
      DIM deltaHeight As CGFloat = height - inWindow.Height
      
      DIM frameRect As NSRect = Frame(inWindow.Handle)
      frameRect.h = frameRect.h + deltaHeight
      frameRect.Y = frameRect.Y - deltaHeight
      frameRect.w = frameRect.w + deltaWidth
      
      SetFrameDisplayAnimate inWindow.Handle, frameRect, TRUE, TRUE
    end if
    
  #else
    me.Width = width
    me.Height = height
  #endif
End Sub
Private Structure NSRect
  x as Double
  y as Double
  w as Double
  h as Double
End Structure
2 Likes

@Emily-Elizabeth_Howard ā€“ thanks. Thatā€™s the Cocoa method Iā€™m using in my C++ code:

[self.window setFrame:newWindowFrame display:YES animate:YES];

ā€¦but itā€™s cool to see how it could be called via Xojo! Thanks!

This Xojo utility Iā€™m writing is going to be Windows only. I had hoped there were corresponding Windows animation methods. I wonder if I could do low-rent window size animation by changing the frame iteratively, and forcing it to be redisplayed? Or maybe the MonkeyBread libraries have support for that kind of animation? (have to ask @Christian_Schmitz about that!)

When I have more than a couple of controls on a page of a page panel I use containers. That way everything is more OO and more organised. The controls are usually private so that the containers need to communicate between each other.

1 Like

@Beatrix_Willius ā€“ great suggestion!

We have NSWindowMBS class with method:

setFrame(frameRect as NSRectMBS, display as boolean, animated as boolean)

Sorry, I canā€˜t resist:

And that means what? This totally UI bullsh** and I hate it for decades. It has absolutely no value to the user and is simply gimmicky.

@Carsten_Belling ā€“ as a UI designer, I find it elegant and helpful. Preference/Option/Setting panels can have a lot of tabs, and itā€™s nice 1) see all that tabā€™s options at once without scrolling, and not to have to either 2) cram all your options into the same small space, or 3) have a tab with a few options and lots of empty white space.

1 Like

@Christian_Schmitz ā€“ so NOT on Windows ā€“ only MacOS?

Animation on Windows? Well, youā€™d better not do that.

1 Like

Because itā€™s flashy? The animation sucks? Even on a modern Windows 10/11 machine?

Because both the declare and the MBS plugin use a macOS only API. I think that might have got a little lost in translation.

OH ā€“ there is no MBS plugin for Windows? (otherwise, Iā€™m not following what the limitation is)

Apple wrote a fancy animated window routine for developers to use. Microsoft did not.