Having reference rect to GUI's and more...

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Having reference rect to GUI's and more...

Post by christianclavet »

Hi.

I'm currently expanding the Irrlicht GUI system in the need of my current project (IRB). I need a "container" window than can contain other GUI's but that we can scroll the content. (Scrolling panels, icon window, etc). My current code is mostly working, but found out that since when we move the scrollers the GUI's are also being moved (and clipped). But there is no reference position/rect to refer to the starting point.

I would propose adding theses methods in IGUIElement.h in the include directory:
A getter:

Code: Select all

IGUIElement::getRerefenceRect()
{
    return referenceRect;
}
A setter:

Code: Select all

IGUIElement::setReferenceRect(rect<s32> rectangle)
{
    referenceRect=rectangle;
}
Initialisation (set referenceRect to 0) and a private rect variable are needed too.

I've not yet implemented this, so if you find a better way of doing this...

In my current GUI, with this I could check all the childrens of the GUI, see if their referenceRect is 0, then put the initial/reference position with the setter.
Then the gui will use the getter to have a reference position when we scroll the window. If you decide to drag or move the item inside the window, you simply update the referenceRect and the GUI will maintain the relative position properly even if the window is being scrolled.

We could use position2D instead, but if the GUI item has changed size, we could also retrieve the information with this referenceRect.

Since it might not be accepted. I will create an array with the rect information directly inside the GUI. This will cause more overhead and might be a slower approach, but will not need patching.

Anyone know if we can clip a GUI from a custom parent clipping rect? I still see stuff not being clipped at the scrollbar. Not a big issue, but could be cleaner if I could clip the children GUI at the scrollbars instead of the frame of the GUI.

As another thing I was thinking of, It would be really interesting to have a template variable that we could set/get in ISceneNode.h to put custom informations (We could create a custom data type with lots of informations and use it there). With this it might be useful a lot for any project to put the "gameobject" or type information inside the node directly.
CuteAlien
Admin
Posts: 9633
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Having reference rect to GUI's and more...

Post by CuteAlien »

Maybe needs a new container which has that information? Have to check how other gui-systems handle this case.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: Having reference rect to GUI's and more...

Post by christianclavet »

Hi, For Irrlicht, they don't handle this at all. The other GUI are drawing directly on the screen their elements. (Fonts, box, etc) They create and draw their elements internally so they have the reference position since it is created there.

What I need to do is to take already made GUI (standard Irrlicht or other custom ones) and scroll them inside a parent window. (So the GUI will manage it's childs).

I'm thinking now how to handle drag & drop and I will have to maintain a list anyway. It not impossible without patching, it's just a little more difficult.
[EDIT]
Ok. Done the basic of it.
Image

I've done a CONTENT WIǸDOW gui that is inside a SCALING WINDOW gui. The 4 blocks of text are child GUI that have been added to the CONTENT window gui and we can scroll over the area. The scaling window support cursor changes.

Here is the current code for this example. When it's good enough to use in IRB, I'll make this also available for Irrlicht (created based on Irrlicht Trunk)

Code: Select all

#include <irrlicht.h>
#include "GUI/CGUIExtWindow.h"
#include "GUI/CGUIConWindow.h"
 
 
using namespace irr;
 
 
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
 
int main()
{
 
    IrrlichtDevice *device =
        createDevice( video::EDT_OPENGL, dimension2d<u32>(640, 480), 16,
            false, false, false, 0);
 
    if (!device)
        return 1;
 
 
    device->setWindowCaption(L"New windows types - Irrlicht Engine Demo");
 
 
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();
 
    smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
 
    //Custom window that can scale (scalable windows / panes)
    CGUIExtWindow* win = new CGUIExtWindow(L"Windows that can scale, first",
        guienv,guienv->getRootGUIElement(),-1,rect<s32>(10,10,400,300));
 
    win->setDevice(device); //Need to set the device first.
    win->setStretchable(true); //Enable the window to be stretched (all directions)
    win->setCloseHide(true); //Will hide the window instead of removing it.
    win->setMinSize(core::dimension2du(320,200)); //Limit of the size
 
 
    guienv->addStaticText(L"This is the Irrlicht OPENGL renderer!",
        rect<s32>(10,30,260,52),true,-1,win);
 
 
    // Creating a content window
    CGUIConWindow* content = new CGUIConWindow(guienv, win,-1,rect<s32>(10,60,250,200));
 
    content->setMaxSize(dimension2du(1000,1000)); //Will be automatic with an overide in the future
    content->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
    content->setDrawBackground(true);
 
 
    IGUIStaticText* Texte=guienv->addStaticText(L"Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress ",
        core::rect<s32>(10,10,240,240),true,true,content);
 
 
    IGUIStaticText* Texte1=guienv->addStaticText(L"Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress ",
        core::rect<s32>(260,10,490,240),true,true,content);
    Texte1->setBackgroundColor(video::SColor(255,255,255,255));
 
    IGUIStaticText* Texte2=guienv->addStaticText(L"Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress ",
        core::rect<s32>(10,260,490,490),true,true,content);
    Texte2->setBackgroundColor(video::SColor(255,240,0,0));
 
    IGUIStaticText* Texte3=guienv->addStaticText(L"Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress - Test in progress ",
        core::rect<s32>(510,260,990,490),true,true,content);
    Texte3->setBackgroundColor(video::SColor(255,255,255,0));
 
 
    while(device->run())
    {
 
        driver->beginScene(true, true, SColor(255,100,101,140));
 
        smgr->drawAll();
        guienv->drawAll();
 
        driver->endScene();
    }
 
 
    device->drop();
 
    return 0;
}
 
Perhaps if the IRRLicht devs have more time they could add these new window types to plain Irrlicht. But the current code I have currently doesnt require ANY patching at all. You include the files and you're ready to go.
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: Having reference rect to GUI's and more...

Post by chronologicaldot »

hm... I tried to edit my post, and now it's coming up blank. Is there a post character limit?
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: Having reference rect to GUI's and more...

Post by chronologicaldot »

I have a class I use for this, which automatically generates scrollbars. No need to modify the engine. It's included in my XPLOsion project, but here's the class if you just want that.

I'm going to have to post it in pieces since it seems to be too big for a single post. Here's a prerequisite file:

WebTypes.h

Code: Select all

 
/*
Created by Nicolaus Anderson, 2012
 
zlib-style license
*/
 
#include <irrlicht.h>
 
#pragma once
 
//! HTML Position type
/* Determines where an element will be drawn on screen. */
enum HTMLPos
{
    HTM_POS_absolute=0,
 
    HTM_POS_relative,
 
    HTM_POS_static,
 
    HTM_POS_fixed
};
 
//! HTML Position type
/* Determines where an element will be drawn on screen. */
const irr::c8* const HTMLPosTypes[] =
{
    "absolute",
    "relative",
    "static",
    "fixed",
    0
};
 
//! HTML Overflow
/* Determines if children should be cropped to stay in the element. */
enum HTMLOverflow
{
    HTM_OVF_show = 0, // don't crop children
    HTM_OVF_hide, // crop children
    HTM_OVF_auto // create a scroll bar
};
 
//! HTML Overflow
/* Determines if children should be cropped to stay in the element. */
const irr::c8* const WebOverflowTypes[] =
{
    "visible",
    "hidden",
    "auto",
    0
};
 
//! HTML Positioned-element
/* All such elements that are meant to be positioned in an HTML-style manner
need to implement this. */
class HTMLPositioned
{
protected:
    /* Contains the type of position that determines where this
    element will be drawn. */
    HTMLPos position_type;
 
public:
    void setPosition( HTMLPos pos_type ) { position_type = pos_type; }
 
    HTMLPos getPosition() { return position_type; }
};
 
 
//! HTML Background image repeat
/* Determines how the background image should be repeated over the
entire object. */
enum HTMLBackgroundImageRepeat
{
    HTM_BIR_no_repeat=0, // no repeat
    HTM_BIR_repeat_x, // only repeat along the x-axis
    HTM_BIR_repeat_y, // only repeat along the y-axis
    HTM_BIR_repeat, // repeat along both the x-axis and the y-axis
};
 
//! HTML Background image repeat
/* Determines how the background image should be repeated over the
entire object. */
const irr::c8* const HTMLBackgroundImageRepeatTypes[] =
{
    "no-repeat",
    "repeat-x",
    "repeat-y",
    "repeat",
    0
};
 
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: Having reference rect to GUI's and more...

Post by chronologicaldot »

sdiv.h

Code: Select all

 
/*
Created by Nicolaus Anderson, 2012
 
zlib-style license.
*/
 
#include <irrlicht.h>
#include "WebTypes.h"
 
#ifndef _INCLUDE_SDIV_H_
#define _INCLUDE_SDIV_H_
 
//! Div class
/*
This class is a GUI box that acts like an HTML division.
It contains information for hiding its child GUI elements.
If its overflow is set to auto, scrollbars are generated
for moving the content within the clipping rectangle of this box.
*/
class divBox : public irr::gui::IGUIElement, public HTMLPositioned
{
protected:
    //irr::video::ITexture * background_image;
    irr::video::IImage* background_image;
    irr::core::recti* image_box;
    irr::core::stringc background_image_name;
    HTMLBackgroundImageRepeat background_image_repeat;
 
    /* Overflow */
    HTMLOverflow overflow;
 
    /* Background colors */
    irr::video::SColor background_color;
    irr::video::SColor border_color;
    bool ifDrawBorder;
 
    /* For handling scrolling when overflow is set to auto. */
    bool has_overflow_horiz;
    bool has_overflow_vert;
    irr::core::vector2di scroll_position; // last position of the scroll bar
    irr::gui::IGUIScrollBar* scrollbar_horiz;
    irr::gui::IGUIScrollBar* scrollbar_vert;
 
    irr::s32 SCROLLBAR_WIDTH;
 
    /* Region occupied by the child GUI elements. */
    irr::core::recti child_bounds;
 
public:
 
        //! Constructor
    /**/
    divBox(
        irr::gui::IGUIEnvironment * env,
        irr::gui::IGUIElement * parent = 0,
        irr::s32 id=-1 )
        : IGUIElement(
            irr::gui::EGUIET_ELEMENT,
            env,
            parent, id,
            irr::core::recti(0,0,0,0)
            )
    {
#ifdef _DEBUG
        setDebugName( "divBox" );
#endif
 
        background_image = 0;
        background_color = irr::video::SColor( 0,0,0,0 );
        border_color = irr::video::SColor( 255,0,0,0 );
        ifDrawBorder = false;
        image_box = 0;
 
        position_type = HTM_POS_static;
        overflow = HTM_OVF_show;
 
        has_overflow_horiz = false;
        has_overflow_vert = false;
        scrollbar_horiz = 0;
        scrollbar_vert = 0;
 
        SCROLLBAR_WIDTH = 20;
    }
 
        //! Destructor
    /**/
    ~divBox()
    {
        if ( scrollbar_horiz != 0 )
            scrollbar_horiz->drop();
 
        if ( scrollbar_vert != 0 )
            scrollbar_vert->drop();
 
        if ( background_image != 0 )
            background_image->drop();
    }
 
        //! Get GUI element type name
    /* Override of the IGUIElement function getTypeName(). */
    const irr::c8* getTypeName() const
    {
        return "divBox";
    }
    
        //! Hides overflow
    /* Indicates if the overflow of this division is hidden. */
    bool hidesOverflow();
 
        //! Show the overflow
    /* Allows that which extends outside of this division's bounding box to be shown. */
    void overflowShow();
    
        //! Hide the overflow
    /* Hides that which extends outside of this division's bounding box. */
    void overflowHide();
 
        //! Automatically handle the overflow
    /* Creates scroll bars to display this division's contents if it extends outside
    of this division's bounding box. */
    void overflowAuto();
 
        //! Convert overflow parameter to string
    /* Converts this div's current HTMLOverflow value to a string and returns it. */
    irr::core::stringc convertOverFlowToString() const;
 
        //! Get overflow
    /* Returns the HTMLOverflow value of this div */
    HTMLOverflow getOverflow();
 
        //! Set overflow
    /* Saves the overflow value to this div */
    void setOverflow( HTMLOverflow new_overflow );
 
        //! Set overflow
    /* Converts a string to an HTMLOverflow value */
    void setOverflowFromString( const irr::c8* overflow_val );
 
        //! Set background color
    /* Sets the default color that will be drawn for this GUI element when it
    is displayed. */
    void setBackgroundColor( irr::video::SColor color ) { background_color = color; }
 
        //! Set background image
    /* Loads the image from the given path and assigns it to this GUI element
    as its background image. */
    void setImage( irr::io::path filename );
 
        //! Set draw outline
    /* Determines if an outline should be draw around the division.
    Note: Current implementation calls for outlines to be drawn under
    anything attached to the edge rather than pushing it inward. */
    void setDrawBorder( bool draw=false );
 
        //! Set border color
    /* Assigns the color of the border to draw. */
    void setBorderColor( irr::video::SColor color );
 
        //! Set scrollbar width
    /* Sets the width of the scroll bars, vertical or horizontal. */
    void setScrollBarWidth( irr::s32 width );
 
        //! Get scroll position
    /* Useful for outside this class if the programmer wants to draw
    other things based on this element's scrollbars' positions. */
    irr::core::vector2di getScrollBorPositions();
 
        //! Draw
    /* For drawing the division. This is called by the engine. */
    virtual void draw();
 
        //! Set relative position
    /* Simple override of IGUIElement::setRelativePosition but also calls for
    the updating of the scroll bars. */
    void setRelativePosition(const irr::core::recti &r);
    void setRelativePosition(const irr::core::position2di &position);
 
        //! Set relative position
    /* Simple override of IGUIElement::setRelativePosition but also calls for
    the updating of the scroll bars. */
    void setRelativePositionProportional(const irr::core::rectf &r);
 
        //! On Event
    /* Response to user input events. */
    virtual bool OnEvent( const irr::SEvent& event );
 
        //! Serialize
    /* For obtaining the key attributes of this GUI element. */
    virtual void serializeAttributes(
        irr::io::IAttributes* out, irr::io::SAttributeReadWriteOptions* options=0
        ) const;
 
        //! Deserialize
    /* For defining this GUI element from key attributes. */
    virtual void deserializeAttributes(
        irr::io::IAttributes* in, irr::io::SAttributeReadWriteOptions* options=0
        );
 
 
    /* Override methods from IGUIElement and methods for keeping the scroll bars
    properly adjusted. */
 
        //! Add Child
    /* Handles adding a child to this GUI element. */
    void addChild(irr::gui::IGUIElement* child);
 
        //! Add Child
    /* Handles adding a child to this GUI element. */
    void addChildToEnd(IGUIElement* child);
 
        //! Remove Child
    /* Handles removing a child from this GUI element. */
    void removeChild(irr::gui::IGUIElement* child);
 
        //! Reset child bounds
    /* Resets the child bounds in case changes were made (e.g. GUI elements
    were made the children of this without it knowing). */
    void resetChildBounds();
 
        //! Reset child positions
    /* Resets the position of the children and the scrollbars. */
    void resetChildPositions();
 
        //! Bring scrollbars to front
    /* Make the scroll bars the first thing that will respond on user
    interaction. */
    void bringScrollsToFront();
 
protected:
 
        //! Draw children
    /* Handles drawing he children and generating scrollbars if necessary. */
    virtual void drawChildren();
 
        //! Get child GUI element boundaries
    /* Returns a rectangle that encompasses all of the child GUI elements. */
    // Recommend this be added to the irrlicht engine.
    irr::core::recti getChildBounds();
 
        //! Update scroll bars
    /* Updates the scroll bar positions. */
    void updateScrollBars( bool rescale );
 
        //! Update horizontal scroll bar
    /* Creates the scroll bar if necessary. Otherwise it simply udates its
    size and location information. This is necessary if the division is
    going to be resized. */
    void updateScrollBarHoriz( bool rescale );
 
        //! Update vertical scroll bar
    /* Creates the scroll bar if necessary. Otherwise it simply udates its
    size and location information. This is necessary if the division is
    going to be resized. */
    void updateScrollBarVert( bool rescale );
};
 
 
//! Div Generator
/* Creates an instance of divBox, assigning it to the root GUI
element if no parent was given. */
irr::gui::IGUIElement* addDivBox(
        irr::gui::IGUIEnvironment*,
        irr::gui::IGUIElement*,
        irr::s32
        );
 
#endif // ifndef _INCLUDE_SDIV_H_
 
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: Having reference rect to GUI's and more...

Post by chronologicaldot »

sdiv.cpp

Code: Select all

 
/*
Created by Nicolaus Anderson, 2012
 
For license terms, see sdiv.h
*/
 
#include "sdiv.h"
 
using namespace irr::gui;
 
#pragma once
 
 
bool divBox::hidesOverflow()
{
    return (overflow == HTM_OVF_hide) || (overflow == HTM_OVF_auto);
}
 
void divBox::overflowShow() { overflow = HTM_OVF_show; }
void divBox::overflowHide() { overflow = HTM_OVF_hide; }
void divBox::overflowAuto() { overflow = HTM_OVF_auto; }
 
 
HTMLOverflow divBox::getOverflow() { return overflow; }
void divBox::setOverflow( HTMLOverflow new_overflow ) { overflow = new_overflow; }
 
 
irr::core::stringc divBox::convertOverFlowToString() const
{
    if ( overflow == HTM_OVF_show )
        return irr::core::stringc( "visible" );
 
    if ( overflow == HTM_OVF_hide )
        return irr::core::stringc( "hidden" );
 
    if ( overflow == HTM_OVF_auto )
        return irr::core::stringc( "auto" );
 
    return " ";
}
 
void divBox::setOverflowFromString( const irr::c8* overflow_val )
{
    irr::core::stringc ovrf = overflow_val;
 
    if ( ovrf == "visible" || ovrf == "show" )
    {
        overflow = HTM_OVF_show;
        return;
    }
 
    if ( ovrf == "hidden" )
    {
        overflow = HTM_OVF_hide;
        return;
    }
 
    if ( ovrf == "auto" )
    {
        overflow = HTM_OVF_auto;
        return;
    }
}
 
 
void divBox::setImage( irr::io::path filename )
{
    if ( image_box != 0 )
    {
        delete image_box;
        image_box = 0;
    }
 
    //background_image = Environment->getVideoDriver()->getTexture( filename );
    background_image = Environment->getVideoDriver()->createImageFromFile( filename );
 
    background_image_name = (irr::core::stringc) filename;
}
 
 
void divBox::setDrawBorder( bool draw )
{
    ifDrawBorder = draw;
}
 
 
void divBox::setBorderColor( irr::video::SColor color )
{
    border_color = color;
}
 
void divBox::setScrollBarWidth( irr::s32 width )
{
    SCROLLBAR_WIDTH = (width>0? width:20);
}
 
irr::core::vector2di divBox::getScrollBorPositions()
{
    return scroll_position;
}
 
void divBox::addChild(irr::gui::IGUIElement* child)
{
    /* Resets the absolute position of the children to their
    original positions so we can add a new one in the appropriate
    location and update the scrollbars. */
    resetChildPositions();
 
    IGUIElement::addChild(child);
 
    child_bounds = getChildBounds();
 
    updateScrollBars(true);
 
    // default position for scrollbars is in front
    bringScrollsToFront();
}
 
void divBox::addChildToEnd(irr::gui::IGUIElement* child)
{
    /* Resets the absolute position of the children to their
    original positions so we can add a new one in the appropriate
    location and update the scrollbars. */
    resetChildPositions();
 
    IGUIElement::addChildToEnd(child);
 
    child_bounds = getChildBounds();
 
    updateScrollBars(true);
 
    // default position for scrollbars is in front
    bringScrollsToFront();
}
 
 
void divBox::removeChild(irr::gui::IGUIElement* child)
{
    /* Resets the absolute position of the children to their
    original positions so we can add a new one in the appropriate
    location and update the scrollbars. */
    resetChildPositions();
 
    IGUIElement::removeChild(child);
 
    child_bounds = getChildBounds();
 
    updateScrollBars(true);
}
 
void divBox::resetChildBounds()
{
    child_bounds = getChildBounds();
}
 
void divBox::resetChildPositions()
{
    irr::core::list<irr::gui::IGUIElement*>::Iterator kid;
 
    kid = Children.begin();
    for ( ; kid != Children.end(); kid++ )
    {
        // skip the scrollbars
        if ( scrollbar_horiz != 0 && *kid == scrollbar_horiz )
            continue;
        if ( scrollbar_vert != 0 && *kid == scrollbar_vert )
            continue;
 
        (*kid)->move( scroll_position );
    }
 
    scroll_position.set( 0, 0 );
 
    if ( scrollbar_horiz != 0 )
        scrollbar_horiz->setPos(0);
 
    if ( scrollbar_vert != 0 )
        scrollbar_vert->setPos(0);
}
 
void divBox::bringScrollsToFront()
{
    if ( scrollbar_horiz )
        bringToFront( scrollbar_horiz );
 
    if ( scrollbar_vert )
        bringToFront( scrollbar_vert );
}
 
 
void divBox::draw()
{
    if ( !IsVisible ) return;
 
    irr::video::IVideoDriver * vid = Environment->getVideoDriver();
 
    irr::core::vector2di image_shift; // location for drawing the background image
 
    // Draw the background color (default is transparent)
    vid->draw2DRectangle( background_color, AbsoluteRect, &AbsoluteClippingRect);
 
    // If there is an image, draw it
    if ( background_image != 0 )
    {
        // Box in which to draw the image
        /* For textures
        if ( image_box == 0 )
            image_box = new irr::core::recti(
                    irr::core::vector2di(0,0),
                    background_image->getOriginalSize()
                    );
 
        vid->draw2DImage(
                background_image,
                AbsoluteRect.UpperLeftCorner,
                *image_box,
                &AbsoluteClippingRect
                );
        */
 
        if ( image_box == 0 )
            image_box = new irr::core::recti(
                    AbsoluteClippingRect.UpperLeftCorner, // upper left corner
                    
                    AbsoluteClippingRect.UpperLeftCorner // lower right corner
                    +
                        // similar to casting the image dimension
                    irr::core::vector2di(
                        background_image->getDimension().Width,
                        background_image->getDimension().Height
                        )
                    );
 
        /* Prepare to draw the image across both the x and y axis,
        only stopping if not supposed to continue. */
 
            // set the starting location for drawing the image
        image_shift = AbsoluteClippingRect.UpperLeftCorner;
 
        // across the width
        while ( image_shift.X < AbsoluteClippingRect.LowerRightCorner.X )
        {
            while ( image_shift.Y < AbsoluteClippingRect.LowerRightCorner.Y )
            {
                for (
                    irr::u32 plx = 0;
                    plx < (irr::u32)image_box->getWidth()
                    &&
                    (irr::s32)plx + image_shift.X < AbsoluteClippingRect.LowerRightCorner.X;
                    plx++
                    )
                {
                    for (
                        irr::u32 ply = 0;
                        ply < (irr::u32)image_box->getHeight()
                        &&
                        (irr::s32)ply + image_shift.Y < AbsoluteClippingRect.LowerRightCorner.Y;
                        ply++ )
                    {
                        vid->drawPixel(
                            plx + (irr::u32)image_shift.X,
                            ply + (irr::u32)image_shift.Y,
                            background_image->getPixel( plx, ply )
                            );
                    }
                }
 
                /* stop drawing if this isn't supposed to be repeated
                along the y-axis or over all */
                if ( background_image_repeat != HTM_BIR_repeat
                    && background_image_repeat != HTM_BIR_repeat_y )
                    break;
 
                // perform shift to start drawing further along
                image_shift.Y += background_image->getDimension().Height;
 
 
            } // end going across the height
 
            /* stop drawing if this isn't supposed to be repeated
            along the x-axis or over all */
            if ( background_image_repeat != HTM_BIR_repeat
                && background_image_repeat != HTM_BIR_repeat_x )
                break;
 
            // perform shift to start drawing further along
            image_shift.X += background_image->getDimension().Width;
 
            // reset
            image_shift.Y = AbsoluteClippingRect.UpperLeftCorner.Y;
 
        } // end going across the width
    }
    
    // If it has a border, draw that too
    if ( ifDrawBorder )
        vid->draw2DRectangleOutline( AbsoluteClippingRect, border_color );
 
    
    // Draw the children and possibly scrollbars.
    drawChildren();
}
 
 
void divBox::drawChildren()
{
    // Convenient iterator
    irr::core::list<irr::gui::IGUIElement*>::Iterator kid;
 
    // Normal drawing
    if ( overflow != HTM_OVF_auto )
    {
        kid = Children.begin();
        for ( ; kid != Children.end(); kid++ )
        {
            // skip the scrollbars
            if ( scrollbar_horiz != 0 && *kid == scrollbar_horiz )
                continue;
            if ( scrollbar_vert != 0 && *kid == scrollbar_vert )
                continue;
 
            (*kid)->draw();
        }
    }
 
    // Automatic drawing
    else {
 
        kid = Children.begin();
        for ( ; kid != Children.end(); kid++ )
        {
            // skip the scrollbars
            if ( scrollbar_horiz != 0 && *kid == scrollbar_horiz )
                continue;
            if ( scrollbar_vert != 0 && *kid == scrollbar_vert )
                continue;
 
            (*kid)->draw();
        }
 
        updateScrollBars(false);
 
        if ( scrollbar_horiz != 0 )
        {
            // Draw the scrollbar
            scrollbar_horiz->draw();
        }
 
        if ( scrollbar_vert != 0 )
        {
            // Draw the scrollbar
            scrollbar_vert->draw();
        }
 
    }
 
}
 
 
irr::core::recti divBox::getChildBounds()
{
    // Convenient iterator
    irr::core::list<irr::gui::IGUIElement*>::Iterator kid;
 
    kid = Children.begin();
 
    // skip the scrollbars
    if ( scrollbar_horiz != 0 && *kid == scrollbar_horiz )
        kid++;
    if ( scrollbar_vert != 0 && *kid == scrollbar_vert )
        kid++;
 
    /* Reset the region occupied by the child GUI elements. */
    if ( kid != Children.end() )
    {
        child_bounds.constrainTo(
            (*kid)->getRelativePosition()
            );
    }
 
    // Find out the bounding area of the children
    for ( ; kid != Children.end(); kid++ )
    {
        // skip the scrollbars
        if ( scrollbar_horiz != 0 && *kid == scrollbar_horiz )
            continue;
        if ( scrollbar_vert != 0 && *kid == scrollbar_vert )
            continue;
 
        child_bounds.addInternalPoint(
            (*kid)->getRelativePosition().UpperLeftCorner
            );
 
        child_bounds.addInternalPoint(
            (*kid)->getRelativePosition().LowerRightCorner
            );
    }
 
    return child_bounds;
}
 
 
void divBox::updateScrollBars( bool rescale )
{
    /* Pre-update check for vertical overflow - allows us to account for it
    when making the horizontal scroll bar. */
    if ( child_bounds.getHeight() > AbsoluteRect.getHeight() )
        has_overflow_vert = true;
 
    updateScrollBarHoriz( rescale );
    updateScrollBarVert( rescale );
}
 
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: Having reference rect to GUI's and more...

Post by chronologicaldot »

sdiv.cpp part 2:

Code: Select all

 
void divBox::updateScrollBarHoriz( bool rescale )
{
    // Is a scroll bar needed?
    if (
        child_bounds.UpperLeftCorner.X < 0
        ||
        child_bounds.LowerRightCorner.X + ( has_overflow_vert?SCROLLBAR_WIDTH:0 )
        >
        AbsoluteRect.getWidth()
        )
    {
        // Does a scroll bar need to be made?
        if ( scrollbar_horiz == 0 )
        {
            scrollbar_horiz =
                Environment->addScrollBar(
                        true, // = horizontal bar
                        irr::core::recti(
                            0,
                            AbsoluteRect.getHeight() - SCROLLBAR_WIDTH,
                            AbsoluteRect.getWidth(),
                            AbsoluteRect.getHeight()
                            ),
                        this
                        /* parent GUI element
                          - Set to a sub-element because we're going to be drawing
                          this from an absolute frame of reference
                          (and we don't want it moved with the other children).
                          */
                        );
 
            scrollbar_horiz->setSmallStep( 5 );
            scrollbar_horiz->setLargeStep( 20 );
 
            scrollbar_horiz->setSubElement( false );
 
        } else {
            scrollbar_horiz->setVisible( true );
 
            // Re-scale if desired
            if ( rescale )
                scrollbar_horiz->setRelativePosition(
                        irr::core::recti(
                            0,
                            AbsoluteRect.getHeight() - SCROLLBAR_WIDTH,
                            AbsoluteRect.getWidth(),
                            AbsoluteRect.getHeight()
                            )
                        );
        }
 
        has_overflow_horiz = true;
 
        irr::s32 gap_x;
 
        /* Checking to see if the scroll bar's maximum will allow us to
        show all of the child GUI elements.
        Note: we leave room for the vertical bar if it exists. */
        gap_x = child_bounds.LowerRightCorner.X
                - AbsoluteRect.getWidth();
 
        if ( gap_x > 0 )
        {
            /* Setting the maximum value for the scroll bar to be
            positioned to. */
            scrollbar_horiz->setMax(
                gap_x + ( has_overflow_vert?SCROLLBAR_WIDTH:0 )
                );
        } else {
            scrollbar_horiz->setMax( ( has_overflow_vert?SCROLLBAR_WIDTH:0 ) );
        }
 
        /* Checking to see if the scroll bar's minimum will allow us to
        show all of the child GUI elements. */
        gap_x = child_bounds.UpperLeftCorner.X;
 
        if ( gap_x < 0 )
        {
            /* Setting the minimum value for the scroll bar to be
            positioned to. */
            scrollbar_horiz->setMin( gap_x );
        } else {
            scrollbar_horiz->setMin( 0 );
        }
    }
    else if (
        child_bounds.UpperLeftCorner.X > 0
        &&
        child_bounds.LowerRightCorner.X + ( has_overflow_vert?SCROLLBAR_WIDTH:0 )
        <
        AbsoluteRect.getWidth()
        )
    {
        // NO HORIZONTAL SCROLL BAR - elements fit
        has_overflow_horiz = false;
 
        if ( scrollbar_horiz != 0 )
            scrollbar_horiz->setVisible( false );
    }
}
 
 
void divBox::updateScrollBarVert( bool rescale )
{
    // Is a scroll bar needed?
    if (
        child_bounds.UpperLeftCorner.Y < 0
        ||
        child_bounds.LowerRightCorner.Y + ( has_overflow_horiz?SCROLLBAR_WIDTH:0 )
        >
        AbsoluteRect.getHeight()
        )
    {
        // Create the vertical scrollbar if it doesn't exist
        if ( scrollbar_vert == 0 )
        {
            scrollbar_vert =
                Environment->addScrollBar(
                        false, // = vertical bar
                        irr::core::recti(
                            AbsoluteRect.getWidth() - SCROLLBAR_WIDTH,
                            0,
                            AbsoluteRect.getWidth(),
                            AbsoluteRect.getHeight()
                            + (has_overflow_horiz? -SCROLLBAR_WIDTH:0)
                            ),
                        this
                        /* parent GUI element
                          - Set to a sub-element because we're going to be drawing
                          this from an absolute frame of reference
                          (and we don't want it moved with the other children).
                          */
                        );
 
            scrollbar_vert->setSmallStep( 5 );
            scrollbar_vert->setLargeStep( 20 );
 
            scrollbar_vert->setSubElement( false );
 
        } else {
            scrollbar_vert->setVisible( true );
 
            // Re-scale if desired
            if ( rescale )
                scrollbar_vert->setRelativePosition(
                        irr::core::recti(
                            AbsoluteRect.getWidth() - SCROLLBAR_WIDTH,
                            0,
                            AbsoluteRect.getWidth(),
                            AbsoluteRect.getHeight()
                            + (has_overflow_horiz? -SCROLLBAR_WIDTH:0)
                            )
                        );
        }
 
        has_overflow_vert = true;
 
        irr::s32 gap_y;
 
        /* Checking to see if the scroll bar's maximum will allow us to
        show all of the child GUI elements.
        Note: we leave room for the horizontal bar if it exists. */
        gap_y = child_bounds.LowerRightCorner.Y
                - AbsoluteRect.getHeight();
 
        if ( gap_y > 0 )
        {
            /* Setting the maximum value for the scroll bar to be
            positioned to. */
            scrollbar_vert->setMax(
                gap_y + ( has_overflow_horiz?SCROLLBAR_WIDTH:0 )
                );
        } else {
            scrollbar_vert->setMax( ( has_overflow_horiz?SCROLLBAR_WIDTH:0 ) );
        }
 
        /* Checking to see if the scroll bar's minimum will allow us to
        show all of the child GUI elements. */
        gap_y = child_bounds.UpperLeftCorner.Y;
 
        if ( gap_y < 0 )
        {
            /* Setting the minimum value for the scroll bar to be
            positioned to. */
            scrollbar_vert->setMin( gap_y );
        } else {
            scrollbar_vert->setMin( 0 );
        }
    }
    else if (
        child_bounds.UpperLeftCorner.Y > 0
        &&
        child_bounds.LowerRightCorner.Y + ( has_overflow_horiz?SCROLLBAR_WIDTH:0 )
        <
        AbsoluteRect.getHeight()
        )
    {
        // NO VERTICAL SCROLL BAR - elements fit
        has_overflow_vert = false;
 
        if ( scrollbar_vert != 0 )
            scrollbar_vert->setVisible( false );
    }
}
 
 
/* ****** Overrides of setRelative Position */
 
void divBox::setRelativePosition(const irr::core::recti &r)
{
    IGUIElement::setRelativePosition(r);
 
    updateScrollBars(true);
}
 
void divBox::setRelativePosition(const irr::core::position2di &position)
{
    IGUIElement::setRelativePosition(position);
 
    updateScrollBars(true);
}
 
void divBox::setRelativePositionProportional(const irr::core::rectf &r)
{
    IGUIElement::setRelativePositionProportional(r);
 
    updateScrollBars(true);
}
 
/* ****** END Overrides of setRelative Position */
 
 
/* In response to user interaction, divisions do nothing more than
focus the activity on them, indicating that something interacted
with them. It is up to the programmer to decide on their response.
Response can be handled using xplo and GUIfunctionFire. */
bool divBox::OnEvent( const irr::SEvent& event )
{
    switch( event.EventType )
    {
    case irr::EET_GUI_EVENT:
 
        switch ( event.GUIEvent.EventType )
        {
        case irr::gui::EGET_ELEMENT_FOCUS_LOST:
 
            if ( event.GUIEvent.Caller == this )
            {
                // Bring the scrollbar elements to the front by default
                bringScrollsToFront();
 
                return false;
            }
 
            break; // end case irr::gui::EGET_ELEMENT_FOCUS_LOST
 
        case irr::gui::EGET_SCROLL_BAR_CHANGED:
 
            /* For shifting the location of children when using automatic overflow setting. */
            irr::core::vector2di child_shift;
 
            /* Identify the shift in location of the GUI element children based
            on the scrollbar's bar location. */
            child_shift.X =
                (scrollbar_horiz?
                scroll_position.X - scrollbar_horiz->getPos()
                : 0 );
 
            child_shift.Y =
                (scrollbar_vert?
                scroll_position.Y - scrollbar_vert->getPos()
                : 0 );
 
 
            // Update the scroll position
 
            if ( scrollbar_horiz )
                scroll_position.X = scrollbar_horiz->getPos();
 
            if ( scrollbar_vert )
                scroll_position.Y = scrollbar_vert->getPos();
 
 
            /* Shift all of the child GUI elements according to the difference
            in current scrollbar position from original position. */
            irr::core::list<irr::gui::IGUIElement*>::Iterator kid = Children.begin();
            for ( ; kid != Children.end(); kid++ )
            {
                // skip the scrollbars
                if ( scrollbar_horiz != 0 && *kid == scrollbar_horiz )
                    continue;
                if ( scrollbar_vert != 0 && *kid == scrollbar_vert )
                    continue;
 
                (*kid)->move( child_shift );
            }
 
            break; // end case irr::gui::EGET_SCROLL_BAR_CHANGED
 
        }
 
        break;
 
    case irr::EET_MOUSE_INPUT_EVENT:
 
        if (event.MouseInput.Event == irr::EMIE_LMOUSE_PRESSED_DOWN)
        {
            if (
                !AbsoluteClippingRect.isPointInside(
                    irr::core::position2d<irr::s32>(
                            event.MouseInput.X, event.MouseInput.Y
                            )
                    )
                )
            {
                Environment->setFocus(this);
                return true;
            }
        }
        break;
 
    default: break;
    }
 
    return IGUIElement::OnEvent( event );
}
 
 
void divBox::serializeAttributes(
        irr::io::IAttributes* out, irr::io::SAttributeReadWriteOptions* options
        ) const
{
    // ensure the usual details are also accounted for
    IGUIElement::serializeAttributes( out, options );
 
    out->addEnum(       "position",         position_type, HTMLPosTypes );
 
    /*
    if ( background_image != 0 )
        out->addTexture("background-image", background_image    );
        */
    if ( background_image != 0 )
        out->addString( "background-image", background_image_name.c_str() );
 
    out->addEnum(       "background-repeat",background_image_repeat,
                        HTMLBackgroundImageRepeatTypes);
 
 
    out->addColor(      "background-color", background_color    );
    out->addColor(      "outline-color",    border_color        );
    out->addBool(       "Border",           ifDrawBorder        );
 
    out->addEnum(       "overflow",         overflow, WebOverflowTypes );
 
    out->addInt(        "scrollbar-width",  SCROLLBAR_WIDTH     );
}
 
 
void divBox::deserializeAttributes(
                irr::io::IAttributes *in,
                irr::io::SAttributeReadWriteOptions *options
                )
{
    // Have the superclass handle the rest of the deserialization
    IGUIElement::deserializeAttributes( in, options );
 
    // Set the position/layout type
    position_type = (HTMLPos) in->getAttributeAsEnumeration( "position", HTMLPosTypes );
 
    // Get the background image
    //background_image = in->getAttributeAsTexture( "background-image" );
    setImage( (irr::io::path) in->getAttributeAsString( "background-image" ) );
 
    // Get the background image repetition style
    background_image_repeat =
        (HTMLBackgroundImageRepeat)
         in->getAttributeAsEnumeration( "background-repeat", HTMLBackgroundImageRepeatTypes );
 
    // Get the background color
    irr::s32 color_attr = in->findAttribute( "background-color" );
    if ( color_attr != -1 )
        background_color = in->getAttributeAsColor( color_attr );
 
    // Identify if there should be an outline   
    if ( in->existsAttribute( "Border" ) && in->getAttributeAsBool( "Border" ) )
    {
        ifDrawBorder = true;
        border_color = in->getAttributeAsColor( "outline-color" );
    }
 
    // Set the overflow
    overflow = (HTMLOverflow) in->getAttributeAsEnumeration( "overflow", WebOverflowTypes );
 
    if ( in->existsAttribute( "scrollbar-width" ) )
        SCROLLBAR_WIDTH = in->getAttributeAsInt( "scrollbar-width" );
}
 
 
 
irr::gui::IGUIElement* addDivBox(
        irr::gui::IGUIEnvironment * env,
        irr::gui::IGUIElement * parent = 0,
        irr::s32 id=-1
        )
{
    divBox* box;
 
    if ( parent == 0 )
        box = new divBox( env, env->getRootGUIElement(), id );
    else
        box = new divBox( env, parent, id );
 
    box->drop();
 
    return (irr::gui::IGUIElement*)box;
}
 
Post Reply