Okay, I have tested the code and cleaned it a little, the current version can be found at:
LayoutController.h
LayoutController.cpp
The code isn't that super, I only started working with the STL for the first time a day before I started this, and I am pretty much still learning C++. So far it works and has no bugs that I have found, but I haven't tried beating it to death yet.
I have personally only tried this with ogre projects.
If you want to try it out, it defines a few classes:
CEGUI::LayoutBinding
CEGUI::LayoutBindingSet
CEGUI::LayoutController
First, you need an instance of LayoutController in your project, and to setup the layout of your windows as normal in absolute metrics.
Then, bind 'Window::EventSized' for the windows you want to control with it, I used the code
Code: Select all
WindowManager::getSingleton().getWindow((utf8*)"Stardawn/Shipbuilder")->
subscribeEvent(Window::EventSized, boost::bind(&ShipBuilderApplication::handleWindowResize, this, _1));
...
bool ShipBuilderApplication::handleWindowResize(const CEGUI::EventArgs& e) {
using namespace CEGUI;
layoutController->updateLayout((utf8*)"Stardawn/Shipbuilder");
return true;
}
The method "updateLayout()" takes the parent window name being resized as a parameter, to optimize which windows get resized. You can also call it without a parameter to update all parent windows tracked by bindings in the LayoutController.
To add the actual sizing bindings for the layout, you need to tell the LayoutController what to track and how to resize the windows.
Code: Select all
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"tabs/right",(utf8*)"Stardawn/Shipbuilder/Tabs",LayoutController::RIGHT_EDGE,(utf8*)"Stardawn/Shipbuilder/Panel",LayoutController::LEFT_EDGE,-10.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"tabs/bottom",(utf8*)"Stardawn/Shipbuilder/Tabs",LayoutController::BOTTOM_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::HEIGHT,-50.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"panel/right",(utf8*)"Stardawn/Shipbuilder/Panel",LayoutController::RIGHT_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::WIDTH,-10.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"panel/left",(utf8*)"Stardawn/Shipbuilder/Panel",LayoutController::LEFT_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::WIDTH,-210.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"panel/bottom",(utf8*)"Stardawn/Shipbuilder/Panel",LayoutController::BOTTOM_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::HEIGHT,-50.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"output/right",(utf8*)"Stardawn/Shipbuilder/TextOutput",LayoutController::RIGHT_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::WIDTH,-10.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"output/top",(utf8*)"Stardawn/Shipbuilder/TextOutput",LayoutController::TOP_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::HEIGHT,-50.0f);
layoutController->addBinding((utf8*)"Stardawn/Shipbuilder",(utf8*)"output/bottom",(utf8*)"Stardawn/Shipbuilder/TextOutput",LayoutController::BOTTOM_EDGE,(utf8*)"Stardawn/Shipbuilder",LayoutController::HEIGHT,-10.0f);
In this case, "Stardawn/Shipbuilder" is the parent window, and it is referenced for its width and height to be able to align windows to hug the right and bottom edges. The corner values however would be relative to it's parent - not these children windows, so we can't use those. Relative to the children, the top left would be 0,0 and the lower right x,y is WIDTH,HEIGHT anyway, so we don't loose any functionality.
The first binding binds the right edge of the window named "tabs" to the left edge of the window called "panel" with a space of 10 pixels.
The second binds the tabs' height to be the same as the parent window, but spaced 50 pixels from the actual bottom.
The next two bind the window "Panel" to have it's right edge and left edge be 10 and 210 pixels distance less than the width of the parent, so it hugs the right edge and is always 200 pixels wide.
Since all bindings treat the corner or edge changes as "resize" requests and not "move" requests moving the right or left edge will always change the width, so you need to move the opposite edge by the same amount to keep the width constant.
Next one binds the height to hug the bottom to within 50 pixels, same as the tabs.
Last three bindings bind the static text field 'TextOutput" to hug the bottom with a 40 pixel height and stretch out to a width of 10 pixels less than the parent window.
Any point on any of these windows, such as the Tabs' x,y or the panel's top edge, never are bound since they never need to move for this layout to resize.
The result of those bindings above look like this in my app:
edit: the menu bar in that pic is not bound at all since it never needs to move or change with the resizing of the window. Also, while it looks like the tabs and panel move vertically they both have fixed y locs, but the tab's panel area is dawn below the relative height of the tab buttons as part of that widget's internal code.
side note: if you don't layout your windows exactly right manually beforehand, they don't look right until the parent window is resized, I call updateLayout() twice in my setup and pushes things around for me and makes them work.
Also, if you bind things 'badly' you can have widgets wander right off the window. Bindings are processed in the order they are placed so you can build heirarchies that are dependant on the results of a binding above it in the list, but if you bind to a window that gets update later in the list, the value you bind to will be based on the last resize.
I am not sure how good the code is - I haven't written much C++ - but it works for me so far. I could use to put in exceptions and such for binding name conflicts but I haven't written my own exceptions before in c++ and such, so I am still figuring some of the stuff out as I go. I hope its useful and I'll fix any problems that are pointed out.
Thanks
edit: url link [tags] fixed