Project

General

Profile

Actions

Support #1372

closed

Resize WGLWidget dynamically on window resize

Added by Rama V over 11 years ago. Updated over 11 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Target version:
Start date:
07/27/2012
Due date:
% Done:

0%

Estimated time:

Description

I have been trying WebGL example to asses Wt for our needs.

I am using the WebGL example that came with the SDK.

I do not understand how I can have the Wglwidget resize dynamically on browser window resize.

I have setup some widgets on test page and added CSS to them and they resize automatically, but not the wglwidget.

wglwidget::resizeGL is there but thats not being called (it seems) until resize() is called with width and height parameters and resize() is giving widget a fixed with and height!

Can you suggest on how to resize glwidget dynamically listening to browser window resize?


Files

GLWebApp.C (3.13 KB) GLWebApp.C Rama V, 07/27/2012 11:55 AM
GLWebApp.css (335 Bytes) GLWebApp.css Rama V, 07/27/2012 11:55 AM
Screen_shot_2012-07-27_at_11.38.55.png (114 KB) Screen_shot_2012-07-27_at_11.38.55.png stretched render screen shot Rama V, 07/27/2012 12:40 PM
Screen_shot_2012-07-30_at_16.35.54.png (72.6 KB) Screen_shot_2012-07-30_at_16.35.54.png Image 1 Rama V, 07/30/2012 05:46 PM
Screen_shot_2012-07-30_at_16.42.39.png (70.7 KB) Screen_shot_2012-07-30_at_16.42.39.png Image 2 Rama V, 07/30/2012 05:46 PM
Screen_shot_2012-07-30_at_16.43.16.png (66.6 KB) Screen_shot_2012-07-30_at_16.43.16.png Image 3 Rama V, 07/30/2012 05:46 PM
Actions #1

Updated by Rama V over 11 years ago

Ok, I have now used paintWidget_resize(WLength::Auto, WLength::Auto); and glContainer_>resize(WLength::Auto, WLength::Auto);

with this, glWidget window resizes with browser resizing, BUT render in the gl widget is highly aliased! It looks like resizeGL is not being called and just some cached image is being resized!?

how to make WGLWidget::resizeGL call on widget resize?

Actions #2

Updated by Wim Dumon over 11 years ago

I can tell you that the problem here is that the viewport() function of opengl is not invoked with the proper parameters. Since aspect ratio changes on resize, you'll have to fix viewport and projection matrices on every resize; it's therefore not a simple thing that is entirely fixed client-side.

The easiest way to solve this, is to use layout managers. WGLWidget uses Wt's 'setLayoutSizeAware()' mechanism to be informed when the widget's size changes. This will cause resize() to be invoked server-side when you resize the window.

So where you now have the PaintWidget, put a WContainerWidget instead. Add a VBoxLayout (or HBoxLayout) to the WContainerWidget, and add the PaintWidget to the layout manager (set margins to zero, make sure that it streches the content to all sides). This should do what you want.

Regards,

Wim.

Actions #3

Updated by Rama V over 11 years ago

Thanks for responding. Although your code sounds logical, I am not finding appropriate methods to use (as WVBoxLayout is not a WContainerWidget by itself!)

Now I have code as below, which is giving nothing but a hung server!

glContainer_ = new WContainerWidget(root());

glContainer_->setStyleClass("glContainerStyle");

glContainer_->resize(WLength::Auto, WLength::Auto);

glContainer_->setInline(false);

glLayoutMgr = new WVBoxLayout(0); //cannot pass glContainer to this constructor

glContainer_addWidget(glLayoutMgr>widget());

glLayoutMgr->setContentsMargins(0, 0, 0, 0);

paintWidget_ = new PaintWidget(0); //previously glContainer_ was passed to this constructor

glLayoutMgr->addWidget(paintWidget_);

paintWidget_->setStyleClass("paintWidgetStyle");

paintWidget_->resize(WLength::Auto, WLength::Auto);

Actions #4

Updated by Rama V over 11 years ago

I also tried in below two ways, this time server runs fine, but no gl render (just a blank background). Looks like gl widget is not added anywhere!

Any ideas?

(1)

glContainer_ = new WContainerWidget(root());

glContainer_->setStyleClass("glContainerStyle");

glContainer_->resize(WLength::Auto, WLength::Auto);

glContainer_->setInline(false);

WContainerWidget *glContainer2 = new WContainerWidget(glContainer_);

glContainer2->setStyleClass("glContainerStyle");

glContainer2->resize(WLength::Auto, WLength::Auto);

glContainer2->setInline(false);

glLayoutMgr = new WVBoxLayout(glContainer_->widget(0));

//glContainer_addWidget(glLayoutMgr>widget());

glLayoutMgr->setContentsMargins(0, 0, 0, 0);

paintWidget_ = new PaintWidget(0);

glLayoutMgr->addWidget(paintWidget_);

paintWidget_->setStyleClass("paintWidgetStyle");

paintWidget_->resize(WLength::Auto, WLength::Auto);

(2)

glContainer_ = new WContainerWidget(root());

glContainer_->setStyleClass("glContainerStyle");

glContainer_->resize(WLength::Auto, WLength::Auto);

glContainer_->setInline(false);

WContainerWidget *glContainer2 = new WContainerWidget(glContainer_);

glContainer2->setStyleClass("glContainerStyle");

glContainer2->resize(WLength::Auto, WLength::Auto);

glContainer2->setInline(false);

glLayoutMgr = new WVBoxLayout(glContainer_->widget(0));

//glContainer_addWidget(glLayoutMgr>widget());

glLayoutMgr->setContentsMargins(0, 0, 0, 0);

paintWidget_ = new PaintWidget(glContainer2);

glLayoutMgr->addWidget(paintWidget_);

paintWidget_->setStyleClass("paintWidgetStyle");

paintWidget_->resize(WLength::Auto, WLength::Auto);

Actions #5

Updated by Rama V over 11 years ago

I think I am wrong in doing,

glLayoutMgr = new WVBoxLayout(glContainer_->widget(0));

What is the alternative?

Actions #6

Updated by Rama V over 11 years ago

I tried glContainer_->setLayout instead of addWidget(..) but still no use. Looks like Wt is far from mature.

Actions #7

Updated by Wim Dumon over 11 years ago

I just tested it and it works as advertised (viewport is properly called so the teapot scales as the window scales, and has nice sharp edges, respecting aspect ratio). The code that I tested:

  WContainerWidget *glContainer2 = new WContainerWidget(glContainer_);
  glContainer2->setStyleClass("glContainerStyle");
  glContainer2->resize(WLength::Auto, WLength::Auto);
  glContainer2->setInline(false);
  WVBoxLayout *glLayoutMgr = new WVBoxLayout();
  glContainer2->setLayout(glLayoutMgr);
  glLayoutMgr->setContentsMargins(0, 0, 0, 0);
  paintWidget_ = new PaintWidget(glContainer2);
  paintWidget_->setShaders(vertexShaderSrc, fragmentShaderSrc);
  glLayoutMgr->addWidget(paintWidget_);
Actions #8

Updated by Rama V over 11 years ago

Ok. This now works but why does it resize only horizontally but not vertically?

Previously I was mising 'glContainer2' parameter to 'paintWidget_ = new PaintWidget(glContainer2);'. Adding it brought the gl widget into its place. But....

Can you try the below three lines just below the code you gave in previous message.

paintWidget_->setStyleClass("paintWidgetStyle");

//paintWidget_->resize(WLength::Auto, WLength::Auto);

paintWidget_->resize(500, 500);

where, the css is,

.paintWidgetStyle {

width:100; height:100;

}

With above code in place as it is, 'Only horizontal resize works!'

Now uncomment paintWidget_resize(WLength::Auto.... and comment out paintWidget_>resize(500...

No Gl Widget display!!! Any suggestions?

(I don't know if CSS styling makes any difference here)

Actions #9

Updated by Wim Dumon over 11 years ago

The horizontal rescale only is a Wt bug, solved in current git. We'll soon release a patchlevel for 3.2.2 to fix it too.

Wim.

Actions #10

Updated by Koen Deforche over 11 years ago

  • Status changed from New to Resolved
  • Assignee set to Koen Deforche
  • Target version set to 3.2.2-p1
Actions #11

Updated by Rama V over 11 years ago

This resize bug (see comments 8 and 9) isn't resolved in the latest patch. I have just downloaded 3.2.2-p1. Still I see only horizontal resize only and no vertical resize of the WGLWidget.

Actions #12

Updated by Wim Dumon over 11 years ago

Probably because the height of the container in which your WGLWidget resides is not properly set? Note that height: 100% probably does not do what you think it does - CSS is not very good at managing vertical space. Wt's layout managers can manage vertical space, so you could write it like this (tested and works for me):

  setTitle("Studio Viewer using WtC++ - WebGL");

  WVBoxLayout *vbox = new WVBoxLayout();
  root()->setLayout(vbox);
  topToolBar = new WContainerWidget(root());
  vbox->addWidget(topToolBar);

  paintWidget_ = 0;

  WHBoxLayout *hbox = new WHBoxLayout();
  vbox->addLayout(hbox);
  paintWidget_ = new PaintWidget(0);
  paintWidget_->setShaders(vertexShaderSrc, fragmentShaderSrc);
  paintWidget_->setAlternativeContent(new WImage("nowebgl.png"));
  hbox->addWidget(paintWidget_, 1);

  WPushButton *loadButton = new WPushButton("Load", topToolBar);
  loadButton->clicked().connect(this, &WebGLDemo::fileLoad);
  WPushButton *changeButton = new WPushButton("Change", topToolBar);
  changeButton->clicked().connect(this, &WebGLDemo::changeGl);

  rightFrame = new WContainerWidget();
  hbox->addWidget(rightFrame);

  rightMenu = new WMenu(Wt::Vertical, rightFrame);
  rightMenu->setStyleClass("rightFrameStyle");
  rightMenu->addItem("Test item", 0);
Actions #13

Updated by Rama V over 11 years ago

100% CSS property works fine when used with GWT and also with standard JS/HTML.

I will give your method a try and see.

Updated by Rama V over 11 years ago

I tried this, but I am afraid still not what I expected. I fail to understand on what basis HBox and VBox layouts resize their widgets. I was assuming for them to respect CSS properties provided to them.

Now I have the below code which results in Image 1 as attached. Along with glwidget both top toolbar and bottom footer bar are also resized. What I need is, whatever the size of browser, top toolbar should occupy 100% width, 5% height and same with footer bar. With regards to gl widget I want it to occupy 90% height sandwiched between the two bars and 90% width giving space for right menu bar, giving the page look & feel of desktop application. But this is not what I see even if I specify CSS properties accordingly.

WVBoxLayout *vbox = new WVBoxLayout();

root()->setLayout(vbox);

topToolBar = new WContainerWidget(root());

vbox->addWidget(topToolBar);

topToolBar->setStyleClass("topToolBarStyle");

WPushButton *loadButton = new WPushButton("Load", topToolBar);

loadButton->setStyleClass("buttonStyle");

loadButton->clicked().connect(this, &WebGLDemo::fileLoad);

WPushButton *changeButton = new WPushButton("Change", topToolBar);

changeButton->setStyleClass("buttonStyle");

changeButton->clicked().connect(this, &WebGLDemo::changeGl);

paintWidget_ = 0;

WHBoxLayout *hbox = new WHBoxLayout();

vbox->addLayout(hbox);

paintWidget_ = new PaintWidget(0);

paintWidget_->setAlternativeContent(new WImage("nowebgl.png"));

hbox->addWidget(paintWidget_, 1);

paintWidget_->setStyleClass("paintWidgetStyle");

//paintWidget_->resize(WLength::Auto, WLength::Auto);

paintWidget_->resize(500, 500);

paintWidget_->setAlternativeContent(new WImage("nowebgl.png"));

rightFrame = new WContainerWidget(root());

rightFrame->setStyleClass("rightFrameStyle");

hbox->addWidget(rightFrame, 1);

rightMenu = new WMenu(Wt::Vertical, rightFrame);

rightMenu->setStyleClass("rightMenuStyle");

for(int i(0); i<10; i)

rightMenu->addItem(WString("Operation {1}").arg(i), 0);

footerBar = new WContainerWidget(root());

footerBar->setStyleClass("footerBarStyle");

footerBar->addWidget(new WText("Testing Wt..."));

vbox->addWidget(footerBar);

When I remove resize option from hbox~~addWidget(rightFrame, 1); resulting in hbox~~>addWidget(rightFrame); I see the page as in Image 2 & Image 3.

On what criteria does the layouts resize? and how can I achieve the behaviour I needed?

Actions #15

Updated by Rama V over 11 years ago

CSS I have is,

.topToolBarStyle {

width:100%;

height:5%;

background-color:grey;

text-align:justify;

border-radius:5px;

}

.buttonStyle {

width:60px;

height:30px;

background-color:orange;

}

.glContainerStyle {

width:90; height:90; float:left; background-color:grey; border-radius:2.5px;

}

.paintWidgetStyle {

width:100; height:100;

}

.rightFrameStyle {

width:10; height:90; float:right; background-color:orange; border-radius:2.5px;

}

.rightMenuStyle {

width:100; height:100; float:right;

}

.footerBarStyle {

clear:both; text-align:left; background-color:grey; border-radius:2.5px; height:5%;

}

Actions #16

Updated by Koen Deforche over 11 years ago

Rama V wrote:

100% CSS property works fine when used with GWT and also with standard JS/HTML.

Sometimes.

See also: http://stackoverflow.com/questions/1622027/percentage-height-html-5-css

And: http://www.w3.org/TR/CSS2/visudet.html#propdef-height



Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.

As to how Wt implements the layout managers, see: http://www.webtoolkit.eu/wt/doc/reference/html/classWt_1_1WBoxLayout.html

The space is divided so that each widget is given its preferred size, and remaining space is divided according to stretch factors among widgets. If not all widgets can be given their preferred size (there is not enough room), then widgets are given a smaller size (down to their minimum size). If necessary, the container (or parent layout) of this layout is resized to meet minimum size requirements. The preferred width or height of a widget is based on its natural size, where it presents its contents without overflowing. WWidget::resize() or (CSS width, height properties) can be used to adjust the preferred size of a widget.

So, in your case:

What I need is, whatever the size of browser, top toolbar should occupy 100% width, 5% height and same with footer bar. With regards to gl widget I want it to occupy 90% height sandwiched between the two bars and 90% width giving space for right menu bar, giving the page look & feel of desktop application.

I'm not sure why you want to resize the height of the footer and header, that's rather uncommon for a desktop application, and the layout managers have in fact been created to implement the more common case of giving header and footer their preferred size and distributing excess space to the middle section.

But if you really want to stick to the 5% rule, here is how you could do it:

#include <Wt/WApplication>
#include <Wt/WText>
#include <Wt/WContainerWidget>
#include <Wt/WVBoxLayout>
#include <Wt/WHBoxLayout>

using namespace Wt;

class Test : public WApplication
{
public:
  Test(const WEnvironment& env) 
   : WApplication(env)
  {
    useStyleSheet("styles.css");

    WVBoxLayout *layout = new WVBoxLayout(root());
    WText *header = new WText("Header");
    header->setStyleClass("header");
    header->setHeight(0);

    WText *left = new WText("Left");
    left->setStyleClass("left");
    left->resize(0, 0);

    WText *right = new WText("Right");
    right->setStyleClass("right");
    right->resize(0, 0);

    WText *footer = new WText("Footer");
    footer->setStyleClass("footer");
    footer->setHeight(0);

    WHBoxLayout *middle = new WHBoxLayout();
    middle->setContentsMargins(0, 0, 0, 0);

    middle->addWidget(left, 90);
    middle->addWidget(right, 10);

    layout->addWidget(header, 5);
    layout->addLayout(middle, 90);
    layout->addWidget(footer, 5);
  }
};

WApplication *createApplication(const WEnvironment& env){
  return new Test(env);
}

int main(int argc, char *argv[]){
  return WRun(argc, argv, createApplication);
}

with styles.css:

.header {
 background: #cc3333;
 padding: 5px;
}

.left {
 background: #cccc33;
 padding: 5px;
}

.right {
 background: #cccccc;
 padding: 5px;
}

.footer {
 background: #33cccc;
 padding: 5px;
}

Now, what is probably nicer is to only stretch the middle section, letting other sections keeping their preferred width and height.

#include <Wt/WApplication>
#include <Wt/WText>
#include <Wt/WContainerWidget>
#include <Wt/WVBoxLayout>
#include <Wt/WHBoxLayout>
#include <iostream>

using namespace Wt;

class Test : public WApplication
{
public:
  Test(const WEnvironment& env) 
   : WApplication(env)
  {
    useStyleSheet("styles.css");

    WVBoxLayout *layout = new WVBoxLayout(root());
    WText *header = new WText("Header");
    header->setStyleClass("header");

    WText *left = new WText("Left");
    left->setStyleClass("left");

    WText *right = new WText("Right");
    right->setStyleClass("right");

    WText *footer = new WText("Footer");
    footer->setStyleClass("footer");

    WHBoxLayout *middle = new WHBoxLayout();
    middle->setContentsMargins(0, 0, 0, 0);

    middle->addWidget(left, 1);
    middle->addWidget(right);

    layout->addWidget(header);
    layout->addLayout(middle, 1);
    layout->addWidget(footer);
  }
};

WApplication *createApplication(const WEnvironment& env){
  return new Test(env);
}

int main(int argc, char *argv[]){
  return WRun(argc, argv, createApplication);
}

And that is something you can't do with pure CSS or standard HTML, or in "mature" toolkits like GWT.

Regards,

koen

Actions #17

Updated by Rama V over 11 years ago

Thanks for the explanation. I will give your methods a try.

Also I was a bit wrong in explaining the behaviour I needed. I want the top and bottom bars to keep fixed height but resizable width, stretching only the middle items by both width and height, when browser is resized.

Actions #18

Updated by Koen Deforche over 11 years ago

  • Status changed from Resolved to Closed
  • Target version changed from 3.2.2-p1 to 3.2.3

Fixed in Wt 3.2.3 RC1.

Actions

Also available in: Atom PDF