Is it possible to create split windows with separate controls in Cinder?

#1

What is the problem? Suppose I want to write an application in which there are several different versions of windows between which I need to switch. Does a sinder allow something like this to be done? As I understand it, initially this cannot be done, since the control is set through App and the creation of a window through the createWindows() creates only a clone of the first window. It is independent and cannot be a child of the first created.

#2

The newly created windows can sign up for their own mouse and keyboard events. So you can do this.

#3

…window through the createWindows() creates only a clone of the first window

This isn’t true. Your application will call the ::draw function once per window, so if you’re not checking which is the current window, you’ll draw the same thing into each one. Once multiple windows are involved, my preference is to remove the overridden App::draw virtual method and use signals instead.

// Written inline so not guaranteed to compile
void YourApp::setup ( )
{
    auto mainWindow = getWindow();
    auto secondWindow = createWindow( ... );

    mainWindow->getSignalDraw().connect ( [=] { drawMainWindow(); } );
    secondWindow->getSignalDraw().connect ( [=] { drawSecondWindow(); } );  
}

void YourApp::drawMainWindow ( )
{
    // getWindow[X]() here refers to mainWindow from above;
    gl::setMatricesWindow ( getWindowSize() ); 
    gl::clear ( Colorf ( 1, 0, 0 ) );
}

void YourApp::drawSecondWindow ( )
{
    // getWindow[X]() here refers to secondWindow from above;
    gl::setMatricesWindow ( getWindowSize() ); 
    gl::clear ( Colorf ( 0, 1, 0 ) );
}

The same goes for mouse/keyboard/touch events as well, you just need to connect to the appropriate signals.

1 Like
#4

Yes, I forgot to say that by default. Thanks for the clarification and for the example! I completely forgot about the signals!
But still, I don’t understand how to create an application with several tabs. Create the first window, then create the rest in turn, but how can I put them inside the first (parent) window? Or is there only a way to emulate this behavior within a single window (draw and switch the type of drawing depending on the user selected “window”)? Or is there still a way to create Tab windows or something similar to MDI?

#5

You could definitely do this purely in cinder, perhaps using the imgui block to handle the UI controls, but to create native UI tabs would require writing OS specific code for each platform.

#6

Hm A good idea! I’ll try to do it! Thank you so much for the tips!

#7

By the way, this code also seems to work:
void TabWindowsApp::setup()
{
mainWindow = getWindow();
Window::Format format;
format.setBorderless();
format.setPos(vec2(10, 10));
format.setSize(vec2(mainWindow->getWidth() - 20, mainWindow->getHeight() - 20));
secondWindow = createWindow(format);

	auto hParentWnd = (HWND)mainWindow->getNative();	
	auto hChildWnd=(HWND)secondWindow->getNative();
	
	::SetWindowLongA(hChildWnd, GWL_STYLE, ::GetWindowLongA(hChildWnd, GWL_STYLE | WS_CHILDWINDOW));
	::SetParent(hChildWnd, hParentWnd);

	mainWindow->getSignalDraw().connect([=] { drawMainWindow(); });
	secondWindow->getSignalDraw().connect([=] { drawSecondWindow(); });
	mainWindow->getSignalClose().connect([=] { closeSecondWindow();});
	mainWindow->getSignalResize().connect([=] { sizeSecondWindow(); });
}

void TabWindowsApp::closeSecondWindow()
{
secondWindow->close();
}

void TabWindowsApp::sizeSecondWindow()
{
secondWindow->setSize(vec2(mainWindow->getWidth() - 20, mainWindow->getHeight() - 20));
}