Added navigation through the GUI using tab and the shift and control keys. Added keyboard navigation for most elements. Fixed that annoying bug where you had to click twice to change focus.

Added IGUIElement::isMyChild, isPointInside,  SEvent.GUIEvent.Element. 
Changed setFocus and removeFocus to return bools.
changed quaternion::toAngleAxis to use iszero. 

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@763 dfc29bdd-3216-0410-991c-e03cc46cb475
master
bitplane 2007-07-07 07:03:54 +00:00
parent 8ab9af9d2e
commit e5dbed93dd
43 changed files with 1070 additions and 193 deletions

View File

@ -37,6 +37,18 @@ Changes in version 1.4 (... 2007)
GUI:
- Added IGUISkin::draw2dRectangle, so skins can override the default highlight.
- EGET_ELEMENT_FOCUS_LOST and EGET_ELEMENT_FOCUSED events can now be absorbed
by returning true in OnEvent. Absorbing these events will cancel the focus
change.
- IGUIEnvironment::setFocus and removeFocus now return bools.
- New SEvent.GUIEvent.Element. Points to a second element that is being
used in the event. During a EGET_ELEMENT_FOCUS_LOST event it points
to the element which would like the focus.
- Fixed the default font icons so they have a black border and are not
invisible in default listboxes. Old font tool textures now keep their color
so colorful fonts are possible by editing the font's texture. The colors of
@ -44,9 +56,36 @@ GUI:
from an image. Added builtInFont.bmp for ease of editing.
- IGUIElement changes:
Most elements can now be accessed using the keyboard. Use space and return
to select or deselect, escape to cancel selection (ie while pressing a
button with space or return), and the cursor keys where appropriate.
Added navigation through the GUI using tab and the shift and control keys.
Use these new methods to control tab navigation:
setTabStop - set this to true if the focus will vist the element.
isTabStop - returns true if the focus will visit the element.
setTabOrder - Sets the order of focus within this tab group,
Only one element in each group should have the same TabOrder number.
Set to -1 to add to the end of the group.
setTabGroup - set this to true if the element is a group that contains
other elements, and can be navigated with ctrl+tab/ctrl+shift+tab.
isTabGroup - returns true if the element is a tab group.
getTabGroup - returns the tab group that the element belongs to.
getNextElement - searches for the next element which would be focused
within the element's children, only useful if you are doing your own
custom navigation.
Added isMychild, to check if an element is descended from this one.
Added isPointInside, which is called by getElementFromPoint. Override this
when making non-rectangular elements.
OnEvent no longer absorbs events by default.
Serialize/deserialize now call getter and setter functions, in case people
override these and don't use the internal protected variables.
added getAbsoluteClippingRect, returns the visible area of an element.
- Added IGUISpinBox, by Michael Zeilfelder (CuteAlien).

View File

@ -0,0 +1,35 @@
// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __E_MESSAGE_BOX_FLAGS_H_INCLUDED__
#define __E_MESSAGE_BOX_FLAGS_H_INCLUDED__
namespace irr
{
namespace gui
{
//! enumeration for message box layout flags
enum EMESSAGE_BOX_FLAG
{
//! Flag for the ok button
EMBF_OK = 0x1,
//! Flag for the cancel button
EMBF_CANCEL = 0x2,
//! Flag for the yes button
EMBF_YES = 0x4,
//! Flag for the no button
EMBF_NO = 0x8,
//! This value is not used. It only forces this enumeration to compile in 32 bit.
EMBF_FORCE_32BIT = 0x7fffffff
};
} // namespace gui
} // namespace irr
#endif

View File

@ -72,6 +72,7 @@ namespace irr
enum EGUI_EVENT_TYPE
{
//! A gui element has lost its focus.
//! GUIEvent.Caller is losing the focus to GUIEvent.Element
EGET_ELEMENT_FOCUS_LOST = 0,
//! A gui element has got the focus.
@ -130,11 +131,12 @@ namespace irr
//! The value of a spin box has changed
EGET_SPINBOX_CHANGED
};
} // end namespace gui
//! Struct for holding event data. An event can be a gui, mouse or keyboard event.
//! SEvents hold information about an event.
struct SEvent
{
EEVENT_TYPE EventType;
@ -146,6 +148,9 @@ struct SEvent
//! IGUIElement who called the event
gui::IGUIElement* Caller;
//! If the event has something to do with another element, it will be held here.
gui::IGUIElement* Element;
//! Type of GUI Event
gui::EGUI_EVENT_TYPE EventType;
@ -217,7 +222,8 @@ public:
virtual ~IEventReceiver() {};
//! called if an event happened. returns true if event was processed
//! called if an event happened.
//! \return Returns true if the event was processed
virtual bool OnEvent(SEvent event) = 0;
};

View File

@ -17,6 +17,7 @@ namespace irr
{
namespace gui
{
class IGUIEnvironment;
enum EGUI_ALIGNMENT
@ -52,10 +53,14 @@ public:
: Parent(0), RelativeRect(rectangle), AbsoluteRect(rectangle),
AbsoluteClippingRect(rectangle), DesiredRect(rectangle),
MaxSize(0,0), MinSize(1,1), IsVisible(true), IsEnabled(true),
IsSubElement(false), NoClip(false), ID(id),
IsSubElement(false), NoClip(false), ID(id), IsTabStop(false), TabOrder(-1), IsTabGroup(false),
AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT),
Environment(environment), Type(type)
{
#ifdef _DEBUG
setDebugName("IGUIElement");
#endif
// if we were given a parent to attach to
if (parent)
parent->addChild(this);
@ -346,7 +351,8 @@ public:
{
IGUIElement* target = 0;
// we have to search from back to front.
// we have to search from back to front, because later children
// might be drawn over the top of earlier ones.
core::list<IGUIElement*>::Iterator it = Children.getLast();
@ -360,12 +366,19 @@ public:
--it;
}
if (AbsoluteClippingRect.isPointInside(point) && IsVisible)
if (IsVisible && isPointInside(point))
target = this;
return target;
}
//! Returns true if a point is within this element.
//! Elements with a shape other than a rectangle will override this method
virtual bool isPointInside(const core::position2d<s32>& point) const
{
return AbsoluteClippingRect.isPointInside(point);
}
//! Adds a GUI element as new child of this element.
virtual void addChild(IGUIElement* child)
@ -464,6 +477,84 @@ public:
IsSubElement = subElement;
}
//! If set to true, the focus will visit this element when using
//! the tab key to cycle through elements.
//! If this element is a tab group (see isTabGroup/setTabGroup) then
//! ctrl+tab will be used instead.
void setTabStop(bool enable)
{
IsTabStop = enable;
}
//! Returns true if this element can be focused by navigating with the tab key
bool isTabStop()
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return IsTabStop;
}
//! Sets the priority of focus when using the tab key to navigate between a group
//! of elements. See setTabGroup, isTabGroup and getTabGroup for information on tab groups.
//! Elements with a lower number are focused first
void setTabOrder(s32 index)
{
// negative = autonumber
if (index < 0)
{
TabOrder = 0;
IGUIElement *el = getTabGroup();
while (IsTabGroup && el && el->Parent)
el = el->Parent;
IGUIElement *first=0, *closest=0;
if (el)
{
// find the highest element number
el->getNextElement(-1, true, IsTabGroup, first, closest, true);
if (first)
{
TabOrder = first->getTabOrder() + 1;
}
}
}
else
TabOrder = index;
}
//! Returns the number in the tab order sequence
s32 getTabOrder()
{
return TabOrder;
}
//! Sets whether this element is a container for a group of elements which
//! can be navigated using the tab key. For example, windows are tab groups.
//! Groups can be navigated using ctrl+tab, providing isTabStop is true.
void setTabGroup(bool isGroup)
{
IsTabGroup = isGroup;
}
//! Returns true if this element is a tab group.
bool isTabGroup()
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return IsTabGroup;
}
//! Returns the container element which holds all elements in this element's
//! tab group.
IGUIElement* getTabGroup()
{
IGUIElement *ret=this;
while (ret && !ret->isTabGroup())
ret = ret->getParent();
return ret;
}
//! Returns true if element is enabled.
virtual bool isEnabled()
{
@ -578,6 +669,105 @@ public:
return e;
}
//! returns true if the given element is a child of this one.
//! \param child: The child element to check
bool isMyChild(IGUIElement* child)
{
if (!child)
return false;
do
{
if (child->Parent)
child = child->Parent;
} while (child->Parent && child != this)
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return child == this;
}
//! searches elements to find the closest next element to tab to
//! \param startOrder: The TabOrder of the current element, -1 if none
//! \param reverse: true if searching for a lower number
//! \param group: true if searching for a higher one
//! \param first: element with the highest/lowest known tab order depending on search direction
//! \param closest: the closest match, depending on tab order and direction
//! \param includeInvisible: includes invisible elements in the search (default=false)
//! \return true if successfully found an element, false to continue searching/fail
bool getNextElement(s32 startOrder, bool reverse, bool group,
IGUIElement*& first, IGUIElement*& closest, bool includeInvisible=false)
{
// we'll stop searching if we find this number
s32 wanted = startOrder + ( reverse ? -1 : 1 );
if (wanted==-2)
wanted = 1073741824; // maximum s32
core::list<IGUIElement*>::Iterator it = Children.begin();
s32 closestOrder, currentOrder;
while(it != Children.end())
{
// ignore invisible elements and their children
if ( ( (*it)->isVisible() || includeInvisible ) &&
(group == true || (*it)->isTabGroup() == false) )
{
// only check tab stops and those with the same group status
if ((*it)->isTabStop() && ((*it)->isTabGroup() == group))
{
currentOrder = (*it)->getTabOrder();
// is this what we're looking for?
if (currentOrder == wanted)
{
closest = *it;
return true;
}
// is it closer than the current closest?
if (closest)
{
closestOrder = closest->getTabOrder();
if ( ( reverse && currentOrder > closestOrder && currentOrder < startOrder)
||(!reverse && currentOrder < closestOrder && currentOrder > startOrder))
{
closest = *it;
}
}
else
if ( (reverse && currentOrder < startOrder) || (!reverse && currentOrder > startOrder) )
{
closest = *it;
}
// is it before the current first?
if (first)
{
closestOrder = first->getTabOrder();
if ( (reverse && closestOrder < currentOrder) || (!reverse && closestOrder > currentOrder) )
{
first = *it;
}
}
else
{
first = *it;
}
}
// search within children
if ((*it)->getNextElement(startOrder, reverse, group, first, closest))
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return true;
}
}
++it;
}
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
//! Returns the type of the gui element.
/** This is needed for the .NET wrapper but will be used
later for serializing and deserializing.
@ -611,8 +801,11 @@ public:
out->addEnum("RightAlign", AlignRight, GUIAlignmentNames);
out->addEnum("TopAlign", AlignTop, GUIAlignmentNames);
out->addEnum("BottomAlign", AlignBottom, GUIAlignmentNames);
out->addBool("Visible", IsVisible );
out->addBool("Enabled", IsEnabled );
out->addBool("Visible", IsVisible);
out->addBool("Enabled", IsEnabled);
out->addBool("TabStop", IsTabStop);
out->addBool("TabGroup", IsTabGroup);
out->addInt("TabOrder", TabOrder);
}
//! Reads attributes of the scene node.
@ -624,6 +817,9 @@ public:
setText(in->getAttributeAsStringW("Caption").c_str());
setVisible(in->getAttributeAsBool("Visible"));
setEnabled(in->getAttributeAsBool("Enabled"));
IsTabStop = in->getAttributeAsBool("TabStop");
IsTabGroup = in->getAttributeAsBool("TabGroup");
TabOrder = in->getAttributeAsBool("TabOrder");
core::position2di p = in->getAttributeAsPosition2d("MaxSize");
setMaxSize(core::dimension2di(p.X,p.Y));
@ -691,6 +887,15 @@ protected:
//! id
s32 ID;
//! tab stop like in windows
bool IsTabStop;
//! tab order
s32 TabOrder;
//! tab groups are containers like windows, use ctrl+tab to navigate
bool IsTabGroup;
//! tells the element how to act when its parent is resized
EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom;

View File

@ -6,9 +6,11 @@
#define __I_GUI_ENVIRONMENT_H_INCLUDED__
#include "IUnknown.h"
#include "IGUIWindow.h"
#include "IGUISkin.h"
#include "rect.h"
#include "EMessageBoxFlags.h"
#include "IEventReceiver.h"
#include "IXMLReader.h"
namespace irr
{
@ -50,6 +52,8 @@ class IGUITab;
class IGUIContextMenu;
class IGUIComboBox;
class IGUIToolBar;
class IGUIButton;
class IGUIWindow;
class IGUIElementFactory;
//! GUI Environment. Used as factory and manager of all other GUI elements.
@ -64,13 +68,19 @@ public:
virtual void drawAll() = 0;
//! Sets the focus to an element.
virtual void setFocus(IGUIElement* element) = 0;
/** Causes a EGET_ELEMENT_FOCUS_LOST event followed by a EGET_ELEMENT_FOCUSED event.
If someone absorbed either of the events, then the focus will not be changed.
\return Returns true on success, false on failure */
virtual bool setFocus(IGUIElement* element) = 0;
//! Returns the element with the focus
virtual IGUIElement* getFocus() = 0;
//! Removes the focus from an element.
virtual void removeFocus(IGUIElement* element) = 0;
/** Causes a EGET_ELEMENT_FOCUS_LOST event. If the event is absorbed then the focus
will not be changed.
\return Returns true on success, false on failure */
virtual bool removeFocus(IGUIElement* element) = 0;
//! Returns if the element has focus
virtual bool hasFocus(IGUIElement* element) = 0;

View File

@ -470,6 +470,18 @@ namespace gui
const core::position2di position, u32 starttime=0, u32 currenttime=0,
bool loop=false, const core::rect<s32>* clip=0) = 0;
//! draws a 2d rectangle.
/** \param element: Pointer to the element which wishes to draw this icon.
This parameter is usually not used by IGUISkin, but can be used for example
by more complex implementations to find out how to draw the part exactly.
\param color: Color of the rectangle to draw. The alpha component specifies how
transparent the rectangle will be.
\param pos: Position of the rectangle.
\param clip: Pointer to rectangle against which the rectangle will be clipped.
If the pointer is null, no clipping will be performed. */
virtual void draw2DRectangle(IGUIElement* element, video::SColor &color,
const core::rect<s32>& pos, const core::rect<s32>* clip = 0) = 0;
//! get the type of this skin
virtual EGUI_SKIN_TYPE getType() const { return EGST_UNKNOWN; };

View File

@ -6,6 +6,7 @@
#define __I_GUI_WINDOW_H_INCLUDED__
#include "IGUIElement.h"
#include "EMessageBoxFlags.h"
namespace irr
{
@ -13,25 +14,6 @@ namespace gui
{
class IGUIButton;
//! enumeration for message box layout flags
enum EMESSAGE_BOX_FLAG
{
//! Flag for the ok button
EMBF_OK = 0x1,
//! Flag for the cancel button
EMBF_CANCEL = 0x2,
//! Flag for the yes button
EMBF_YES = 0x4,
//! Flag for the no button
EMBF_NO = 0x8,
//! This value is not used. It only forces this enumeration to compile in 32 bit.
EMBF_FORCE_32BIT = 0x7fffffff
};
//! Default moveable window GUI element with border, caption and close icons.
class IGUIWindow : public IGUIElement
{

View File

@ -473,7 +473,7 @@ inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const
{
f32 scale = sqrt (X*X + Y*Y + Z*Z);
if (core::equals(scale,0.0f) || W > 1.0f || W < -1.0f)
if (core::iszero(scale) || W > 1.0f || W < -1.0f)
{
angle = 0.0f;
axis.X = 0.0f;

View File

@ -30,6 +30,10 @@ CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
// reset sprites
for (u32 i=0; i<EGBS_COUNT; ++i)
ButtonSprites[i].Index = -1;
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
}
@ -101,12 +105,17 @@ bool CGUIButton::OnEvent(SEvent event)
return true;
}
if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
{
setPressed(false);
return true;
}
else
if (!event.KeyInput.PressedDown && Pressed &&
(event.KeyInput.Key == KEY_RETURN ||
event.KeyInput.Key == KEY_SPACE))
{
Environment->removeFocus(this);
//Environment->removeFocus(this);
if (!IsPushButton)
setPressed(false);
@ -116,6 +125,7 @@ bool CGUIButton::OnEvent(SEvent event)
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
Parent->OnEvent(newEvent);
}
@ -125,7 +135,7 @@ bool CGUIButton::OnEvent(SEvent event)
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == (IGUIElement*) this && !IsPushButton)
if (event.GUIEvent.Caller == this && !IsPushButton)
setPressed(false);
}
break;
@ -149,7 +159,7 @@ bool CGUIButton::OnEvent(SEvent event)
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
{
bool wasPressed = Pressed;
Environment->removeFocus(this);
//Environment->removeFocus(this);
if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )
{
@ -171,6 +181,7 @@ bool CGUIButton::OnEvent(SEvent event)
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
Parent->OnEvent(newEvent);
}

View File

@ -21,6 +21,10 @@ CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIEleme
#ifdef _DEBUG
setDebugName("CGUICheckBox");
#endif
// this element can be tabbed into
setTabStop(true);
setTabOrder(-1);
}
@ -37,10 +41,43 @@ bool CGUICheckBox::OnEvent(SEvent event)
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == KEY_RETURN ||
event.KeyInput.Key == KEY_SPACE))
{
Pressed = true;
return true;
}
else
if (Pressed && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
{
Pressed = false;
return true;
}
else
if (!event.KeyInput.PressedDown && Pressed &&
(event.KeyInput.Key == KEY_RETURN ||
event.KeyInput.Key == KEY_SPACE))
{
Pressed = false;
if (Parent)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
Checked = !Checked;
newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == (IGUIElement*)this)
if (event.GUIEvent.Caller == this)
Pressed = false;
}
break;
@ -70,6 +107,7 @@ bool CGUICheckBox::OnEvent(SEvent event)
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
Checked = !Checked;
newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED;
Parent->OnEvent(newEvent);

View File

@ -73,6 +73,7 @@ CGUIColorSelectDialog::CGUIColorSelectDialog( const wchar_t* title, IGUIEnvironm
CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL));
}
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CloseButton->grab();
@ -463,6 +464,7 @@ void CGUIColorSelectDialog::sendSelectedEvent()
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_SELECTED;
Parent->OnEvent(event);
}
@ -473,6 +475,7 @@ void CGUIColorSelectDialog::sendCancelEvent()
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED;
Parent->OnEvent(event);
}

View File

@ -21,7 +21,7 @@ namespace gui
CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle)
: IGUIComboBox(environment, parent, id, rectangle),
ListButton(0), ListBox(0), Selected(-1)
ListButton(0), ListBox(0), Selected(-1), HasFocus(false), LastFocus(0)
{
#ifdef _DEBUG
setDebugName("CGUICheckBox");
@ -48,8 +48,14 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
}
ListButton->setSubElement(true);
ListButton->setTabStop(false);
setNotClipped(true);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
}
@ -148,10 +154,75 @@ bool CGUIComboBox::OnEvent(SEvent event)
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (ListBox && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
{
// hide list box
openCloseMenu();
return true;
}
else
if (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)
{
if (!event.KeyInput.PressedDown)
openCloseMenu();
ListButton->setPressed(ListBox == 0);
return true;
}
else
if (event.KeyInput.PressedDown)
{
s32 oldSelected = Selected;
bool absorb = true;
switch (event.KeyInput.Key)
{
case KEY_DOWN:
Selected += 1;
break;
case KEY_UP:
Selected -= 1;
break;
case KEY_HOME:
case KEY_PRIOR:
Selected = 0;
break;
case KEY_END:
case KEY_NEXT:
Selected = (s32)Items.size()-1;
break;
default:
absorb = false;
}
if (Selected <0)
Selected = 0;
else
if (Selected >= (s32)Items.size())
Selected = (s32)Items.size() -1;
if (Selected != oldSelected)
sendSelectionChangedEvent();
if (absorb)
return true;
}
break;
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
if (Environment->hasFocus(ListBox) &&
event.GUIEvent.Element != this &&
event.GUIEvent.Element != ListButton)
{
openCloseMenu();
}
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == ListButton)
{
@ -179,22 +250,12 @@ bool CGUIComboBox::OnEvent(SEvent event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
{
if (!ListBox)
Environment->removeFocus(this);
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
// send to list box
if (ListBox && ListBox->getAbsolutePosition().isPointInside(p) &&
ListBox->OnEvent(event))
if (ListBox && ListBox->isPointInside(p) && ListBox->OnEvent(event))
return true;
// check if it is outside
if (!AbsoluteClippingRect.isPointInside(p))
{
Environment->removeFocus(this);
return false;
}
return true;
}
case EMIE_LMOUSE_LEFT_UP:
@ -235,6 +296,7 @@ void CGUIComboBox::sendSelectionChangedEvent()
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_COMBO_BOX_CHANGED;
Parent->OnEvent(event);
}
@ -249,6 +311,12 @@ void CGUIComboBox::draw()
return;
IGUISkin* skin = Environment->getSkin();
IGUIElement *currentFocus = Environment->getFocus();
if (currentFocus != LastFocus)
{
HasFocus = currentFocus == this || isMyChild(currentFocus);
LastFocus = currentFocus;
}
core::rect<s32> frameRect(AbsoluteRect);
@ -263,11 +331,16 @@ void CGUIComboBox::draw()
{
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.X += 2;
frameRect.UpperLeftCorner.Y += 2;
frameRect.LowerRightCorner.X -= ListButton->getAbsolutePosition().getWidth() + 2;
frameRect.LowerRightCorner.Y -= 2;
if (HasFocus)
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
IGUIFont* font = skin->getFont();
if (font)
font->draw(Items[Selected].c_str(), frameRect,
skin->getColor(EGDC_BUTTON_TEXT),
skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT),
false, true, &AbsoluteClippingRect);
}
@ -281,6 +354,7 @@ void CGUIComboBox::openCloseMenu()
if (ListBox)
{
// close list box
Environment->setFocus(this);
ListBox->remove();
ListBox = 0;
}

View File

@ -72,7 +72,9 @@ namespace gui
IGUIButton* ListButton;
IGUIListBox* ListBox;
core::array< core::stringw > Items;
s32 Selected;
s32 Selected;
bool HasFocus;
IGUIElement *LastFocus;
};

View File

@ -21,7 +21,7 @@ namespace gui
CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment,
IGUIElement* parent, s32 id,
core::rect<s32> rectangle, bool getFocus)
: IGUIContextMenu(environment, parent, id, rectangle), HighLighted(-1), ChangeTime(0)
: IGUIContextMenu(environment, parent, id, rectangle), HighLighted(-1), ChangeTime(0), EventParent(0)
{
#ifdef _DEBUG
setDebugName("CGUIContextMenu");
@ -210,11 +210,13 @@ bool CGUIContextMenu::OnEvent(SEvent event)
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case gui::EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == (IGUIElement*)this)
case EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == this)
{
// set event parent of submenus
setEventParent(Parent);
remove();
return true;
return false;
}
break;
}
@ -286,7 +288,7 @@ s32 CGUIContextMenu::sendClick(core::position2d<s32> p)
}
// check click on myself
if (AbsoluteClippingRect.isPointInside(p) &&
if (isPointInside(p) &&
HighLighted >= 0 && HighLighted <(s32)Items.size())
{
if (!Items[HighLighted].Enabled ||
@ -297,8 +299,13 @@ s32 CGUIContextMenu::sendClick(core::position2d<s32> p)
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED;
Parent->OnEvent(event);
if (Parent)
Parent->OnEvent(event);
else
if (EventParent)
EventParent->OnEvent(event);
return 1;
}
@ -385,8 +392,6 @@ void CGUIContextMenu::draw()
IGUIFont* font = skin->getFont(EGDF_MENU);
IGUISpriteBank* sprites = skin->getSpriteBank();
video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> rect = AbsoluteRect;
core::rect<s32>* clip = 0;
@ -408,11 +413,11 @@ void CGUIContextMenu::draw()
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
rect.UpperLeftCorner.X += 5;
rect.LowerRightCorner.X -= 5;
driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), rect, clip);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), rect, clip);
rect.LowerRightCorner.Y += 1;
rect.UpperLeftCorner.Y += 1;
driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
y += 10;
}
@ -429,7 +434,7 @@ void CGUIContextMenu::draw()
r.UpperLeftCorner.Y = rect.UpperLeftCorner.Y;
r.LowerRightCorner.X -= 5;
r.UpperLeftCorner.X += 5;
driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), r, clip);
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), r, clip);
}
// draw text
@ -663,6 +668,18 @@ void CGUIContextMenu::deserializeAttributes(io::IAttributes* in, io::SAttributeR
}
// because sometimes the element has no parent at click time
void CGUIContextMenu::setEventParent(IGUIElement *parent)
{
EventParent = parent;
for (u32 i=0; i<(s32)Items.size(); ++i)
if (Items[i].SubMenu)
{
Items[i].SubMenu->setEventParent(parent);
}
}
} // end namespace
} // end namespace

View File

@ -87,6 +87,12 @@ namespace gui
//! Adds a sub menu from an element that already exists.
virtual void setSubMenu(s32 index, CGUIContextMenu* menu);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options);
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
protected:
struct SItem
@ -118,16 +124,13 @@ namespace gui
//! Gets drawing rect of Item
virtual core::rect<s32> getRect(const SItem& i, const core::rect<s32>& absolute);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options);
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
void setEventParent(IGUIElement *parent);
s32 HighLighted;
core::array<SItem> Items;
core::position2d<s32> Pos;
u32 ChangeTime;
IGUIElement* EventParent;
};
} // end namespace gui

View File

@ -48,6 +48,10 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* envi
if (Operator)
Operator->grab();
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
breakText();
}
@ -146,7 +150,7 @@ bool CGUIEditBox::OnEvent(SEvent event)
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == (IGUIElement*)this)
if (event.GUIEvent.Caller == this)
{
MouseMarking = false;
MarkBegin = 0;
@ -377,6 +381,7 @@ bool CGUIEditBox::processKey(const SEvent& event)
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_EDITBOX_ENTER;
Parent->OnEvent(e);
}
@ -424,6 +429,7 @@ bool CGUIEditBox::processKey(const SEvent& event)
BlinkStartTime = os::Timer::getTime();
break;
case KEY_UP:
if (MultiLine || (WordWrap && BrokenText.size() > 1) )
{
s32 lineNo = getLineFromPos(CursorPos);
s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd);
@ -448,8 +454,13 @@ bool CGUIEditBox::processKey(const SEvent& event)
}
}
else
{
return false;
}
break;
case KEY_DOWN:
if (MultiLine || (WordWrap && BrokenText.size() > 1) )
{
s32 lineNo = getLineFromPos(CursorPos);
s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd);
@ -474,6 +485,10 @@ bool CGUIEditBox::processKey(const SEvent& event)
}
}
else
{
return false;
}
break;
case KEY_BACK:
@ -717,7 +732,7 @@ void CGUIEditBox::draw()
CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin;
// draw mark
driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect);
// draw marked text
s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos);
@ -870,8 +885,6 @@ bool CGUIEditBox::processMouse(const SEvent& event)
if (!AbsoluteClippingRect.isPointInside(
core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y)))
{
// remove focus
Environment->removeFocus(this);
return false;
}
else

View File

@ -80,6 +80,10 @@ CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* drive
ToolTip.LastTime = 0;
ToolTip.LaunchTime = 1000;
ToolTip.Element = 0;
// environment is root tab group
Environment = this;
setTabGroup(true);
}
@ -194,30 +198,79 @@ void CGUIEnvironment::drawAll()
//! sets the focus to an element
void CGUIEnvironment::setFocus(IGUIElement* element)
bool CGUIEnvironment::setFocus(IGUIElement* element)
{
if (Focus == element)
return;
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
// GUI Environment should not get the focus
if (element == this)
element = 0;
removeFocus(Focus);
Focus = element;
// stop element from being deleted
if (element)
element->grab();
// focus may change or be removed in this call
IGUIElement *currentFocus = 0;
if (Focus)
{
Focus->grab();
currentFocus = Focus;
currentFocus->grab();
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = Focus;
e.GUIEvent.Element = element;
e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST;
if (Focus->OnEvent(e))
{
if (element)
element->drop();
currentFocus->drop();
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
currentFocus->drop();
currentFocus = 0;
}
if (element)
{
currentFocus = Focus;
if (currentFocus)
currentFocus->grab();
// send focused event
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = Focus;
e.GUIEvent.Caller = element;
e.GUIEvent.Element = Focus;
e.GUIEvent.EventType = EGET_ELEMENT_FOCUSED;
Focus->OnEvent(e);
if (element->OnEvent(e))
{
if (element)
element->drop();
if (currentFocus)
currentFocus->drop();
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
}
if (currentFocus)
currentFocus->drop();
if (Focus)
Focus->drop();
// element is the new focus so it doesn't have to be dropped
Focus = element;
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return true;
}
//! returns the element with the focus
@ -228,19 +281,29 @@ IGUIElement* CGUIEnvironment::getFocus()
//! removes the focus from an element
void CGUIEnvironment::removeFocus(IGUIElement* element)
bool CGUIEnvironment::removeFocus(IGUIElement* element)
{
if (Focus && Focus==element)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = Focus;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST;
Focus->OnEvent(e);
if (Focus)
Focus->drop();
if (Focus->OnEvent(e))
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
}
if (Focus)
{
Focus->drop();
Focus = 0;
}
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return true;
}
@ -429,23 +492,40 @@ bool CGUIEnvironment::postEventFromUser(SEvent event)
break;
case EET_MOUSE_INPUT_EVENT:
// sending input to focus, stopping of focus processed input
updateHoveredElement(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
if ( (Hovered && Hovered != Focus) || !Focus )
{
setFocus(Hovered);
}
// sending input to focus
if (Focus && Focus->OnEvent(event))
return true;
if (!Focus) // focus could have died in last call
{
// trying to send input to hovered element
updateHoveredElement(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
// focus could have died in last call
if (!Focus && Hovered)
return Hovered->OnEvent(event);
if (Hovered && Hovered != this)
return Hovered->OnEvent(event);
}
break;
case EET_KEY_INPUT_EVENT:
if (Focus && Focus != this)
return Focus->OnEvent(event);
{
// send focus changing event
if (event.EventType == EET_KEY_INPUT_EVENT &&
event.KeyInput.PressedDown &&
event.KeyInput.Key == KEY_TAB)
{
IGUIElement *next = getNextElement(event.KeyInput.Shift, event.KeyInput.Control);
if (next && next != Focus)
{
if (setFocus(next))
return true;
}
}
if (Focus)
return Focus->OnEvent(event);
}
break;
} // end switch
@ -1351,6 +1431,56 @@ IGUIElement* CGUIEnvironment::getRootGUIElement()
return this;
}
//! Returns the next element in the tab group starting at the focused element
IGUIElement* CGUIEnvironment::getNextElement(bool reverse, bool group)
{
// start the search at the root of the current tab group
IGUIElement *startPos = Focus ? Focus->getTabGroup() : 0;
s32 startOrder = -1;
// if we're searching for a group
if (group && startPos)
{
startOrder = startPos->getTabOrder();
}
else
if (!group && Focus && !Focus->isTabGroup())
{
startOrder = Focus->getTabOrder();
if (startOrder == -1)
{
// this element is not part of the tab cycle,
// but its parent might be...
IGUIElement *el = Focus;
while (el && el->getParent() && startOrder == -1)
{
el = el->getParent();
startOrder = el->getTabOrder();
}
}
}
if (group || !startPos)
startPos = this; // start at the root
// find the element
IGUIElement *closest = 0;
IGUIElement *first = 0;
startPos->getNextElement(startOrder, reverse, group, first, closest);
IGUIElement *ret = 0;
if (closest)
ret = closest; // we found an element
else if (first)
ret = first; // go to the end or the start
else if (group)
ret = this; // no group found? root group
return ret;
}
//! creates an GUI Environment

View File

@ -151,10 +151,10 @@ public:
IGUIElement* parent=0, s32 id=-1);
//! sets the focus to an element
virtual void setFocus(IGUIElement* element);
virtual bool setFocus(IGUIElement* element);
//! removes the focus from an element
virtual void removeFocus(IGUIElement* element);
virtual bool removeFocus(IGUIElement* element);
//! Returns if the element has focus
virtual bool hasFocus(IGUIElement* element);
@ -229,6 +229,8 @@ public:
private:
IGUIElement* getNextElement(bool reverse=false, bool group=false);
struct SFont
{
core::stringc Filename;

View File

@ -52,6 +52,7 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t* title, IGUIEnvironment* en
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close");
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
if (sprites)
{
CloseButton->setSpriteBank(sprites);
@ -90,6 +91,8 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t* title, IGUIEnvironment* en
if (FileSystem)
FileSystem->grab();
setTabGroup(true);
fillListBox();
}
@ -202,7 +205,6 @@ bool CGUIFileOpenDialog::OnEvent(SEvent event)
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
Environment->removeFocus(this);
return true;
case EMIE_MOUSE_MOVED:
if (Dragging)
@ -293,6 +295,7 @@ void CGUIFileOpenDialog::sendSelectedEvent()
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_SELECTED;
Parent->OnEvent(event);
}
@ -303,6 +306,7 @@ void CGUIFileOpenDialog::sendCancelEvent()
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED;
Parent->OnEvent(event);
}

View File

@ -89,7 +89,7 @@ void CGUIImage::draw()
}
else
{
driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), AbsoluteRect, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_DARK_SHADOW), AbsoluteRect, &AbsoluteClippingRect);
}
IGUIElement::draw();

View File

@ -36,6 +36,7 @@ CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent,
core::rect<s32>(RelativeRect.getWidth() - s, 0, RelativeRect.getWidth(), RelativeRect.getHeight()),
!clip);
ScrollBar->setSubElement(true);
ScrollBar->setTabStop(false);
ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
ScrollBar->drop();
@ -43,6 +44,10 @@ CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent,
ScrollBar->grab();
setNotClipped(!clip);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
updateAbsolutePosition();
}
@ -182,6 +187,8 @@ void CGUIListBox::setSelected(s32 id)
Selected = id;
selectTime = os::Timer::getTime();
recalculateScrollPos();
}
@ -191,19 +198,84 @@ bool CGUIListBox::OnEvent(SEvent event)
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == KEY_DOWN ||
event.KeyInput.Key == KEY_UP ||
event.KeyInput.Key == KEY_HOME ||
event.KeyInput.Key == KEY_END ||
event.KeyInput.Key == KEY_NEXT ||
event.KeyInput.Key == KEY_PRIOR ) )
{
s32 oldSelected = Selected;
switch (event.KeyInput.Key)
{
case KEY_DOWN:
Selected += 1;
break;
case KEY_UP:
Selected -= 1;
break;
case KEY_HOME:
Selected = 0;
break;
case KEY_END:
Selected = (s32)Items.size()-1;
break;
case KEY_NEXT:
Selected += AbsoluteRect.getHeight() / ItemHeight;
break;
case KEY_PRIOR:
Selected -= AbsoluteRect.getHeight() / ItemHeight;
}
if (Selected >= (s32)Items.size())
Selected = Items.size() - 1;
else
if (Selected<0)
Selected = 0;
recalculateScrollPos();
// post the news
if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
Parent->OnEvent(e);
}
return true;
}
else
if (!event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE ) )
{
if (Parent)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN;
Parent->OnEvent(e);
}
return true;
}
break;
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case gui::EGET_SCROLL_BAR_CHANGED:
if (event.GUIEvent.Caller == ScrollBar)
{
// s32 pos = ((gui::IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
return true;
}
break;
case gui::EGET_ELEMENT_FOCUS_LOST:
{
if (event.GUIEvent.Caller == (IGUIElement*)this)
if (event.GUIEvent.Caller == this)
Selecting = false;
}
}
@ -226,35 +298,36 @@ bool CGUIListBox::OnEvent(SEvent event)
if (Environment->hasFocus(this) &&
ScrollBar == el &&
ScrollBar->OnEvent(event))
{
return true;
}
}
Selecting = true;
Environment->setFocus(this);
return true;
}
case EMIE_LMOUSE_LEFT_UP:
if (Environment->hasFocus(this) &&
ScrollBar->getAbsolutePosition().isPointInside(p) &&
ScrollBar->isPointInside(p) &&
ScrollBar->OnEvent(event))
return true;
if (!AbsoluteRect.isPointInside(p))
if (!isPointInside(p))
{
Selecting = false;
Environment->removeFocus(this);
//Environment->removeFocus(this);
break;
}
Selecting = false;
Environment->removeFocus(this);
Selecting = false;
selectNew(event.MouseInput.Y);
return true;
case EMIE_MOUSE_MOVED:
if (Selecting || MoveOverSelect)
{
if (getAbsolutePosition().isPointInside(p))
if (isPointInside(p))
{
selectNew(event.MouseInput.Y, true);
return true;
@ -291,6 +364,7 @@ void CGUIListBox::selectNew(s32 ypos, bool onlyHover)
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = (Selected != oldSelected) ? EGET_LISTBOX_CHANGED : EGET_LISTBOX_SELECTED_AGAIN;
Parent->OnEvent(event);
}
@ -313,7 +387,6 @@ void CGUIListBox::draw()
recalculateItemHeight(); // if the font changed
IGUISkin* skin = Environment->getSkin();
irr::video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32>* clipRect = 0;
@ -349,7 +422,7 @@ void CGUIListBox::draw()
frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y)
{
if (i == Selected)
driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip);
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip);
core::rect<s32> textRect = frameRect;
textRect.UpperLeftCorner.X += 3;
@ -419,6 +492,20 @@ void CGUIListBox::setSpriteBank(IGUISpriteBank* bank)
if (IconBank)
IconBank->grab();
}
void CGUIListBox::recalculateScrollPos()
{
s32 selPos = Selected * ItemHeight - ScrollBar->getPos();
if (selPos < 0)
{
ScrollBar->setPos(ScrollBar->getPos() + selPos);
}
else
if (selPos > AbsoluteRect.getHeight() - ItemHeight)
{
ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight);
}
}
//! Writes attributes of the element.

View File

@ -92,6 +92,7 @@ namespace gui
void recalculateItemHeight();
void selectNew(s32 ypos, bool onlyHover=false);
void recalculateScrollPos();
core::array< ListItem > Items;
s32 Selected;

View File

@ -99,9 +99,13 @@ bool CGUIMenu::OnEvent(SEvent event)
switch(event.GUIEvent.EventType)
{
case gui::EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == (IGUIElement*)this)
if (event.GUIEvent.Caller == this)
closeAllSubMenus();
return true;
break;
case gui::EGET_ELEMENT_FOCUSED:
if (event.GUIEvent.Caller == this && Parent)
Parent->bringToFront(this);
}
break;
case EET_MOUSE_INPUT_EVENT:

View File

@ -111,20 +111,20 @@ void CGUIMeshViewer::draw()
core::rect<s32> frameRect(AbsoluteRect);
frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + 1;
driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);
frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y;
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + 1;
driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - 1;
driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - 1;
frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y;
driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
// draw the mesh

View File

@ -19,7 +19,7 @@ CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* capt
IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: CGUIWindow(environment, parent, id, rectangle),
OkButton(0), CancelButton(0), YesButton(0), NoButton(0), StaticText(0),
Flags(flags), MessageText(text)
Flags(flags), MessageText(text), Pressed(false)
{
#ifdef _DEBUG
setDebugName("CGUIMessageBox");
@ -220,7 +220,7 @@ void CGUIMessageBox::refreshControls()
NoButton = 0;
}
if (Environment->getFocus() == this && focusMe)
if (Environment->hasFocus(this) && focusMe)
Environment->setFocus(focusMe);
}
@ -251,9 +251,97 @@ bool CGUIMessageBox::OnEvent(SEvent event)
SEvent outevent;
outevent.EventType = EET_GUI_EVENT;
outevent.GUIEvent.Caller = this;
outevent.GUIEvent.Element = 0;
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case KEY_RETURN:
if (OkButton)
{
OkButton->setPressed(true);
Pressed = true;
}
break;
case KEY_KEY_Y:
if (YesButton)
{
YesButton->setPressed(true);
Pressed = true;
}
break;
case KEY_KEY_N:
if (NoButton)
{
NoButton->setPressed(true);
Pressed = true;
}
break;
case KEY_ESCAPE:
if (Pressed)
{
// cancel press
if (OkButton) OkButton->setPressed(false);
if (YesButton) OkButton->setPressed(false);
if (NoButton) OkButton->setPressed(false);
Pressed = false;
}
else
if (CancelButton)
{
CancelButton->setPressed(true);
Pressed = true;
}
else
if (CloseButton && CloseButton->isVisible())
{
CloseButton->setPressed(true);
Pressed = true;
}
}
}
else
if (Pressed)
{
if (OkButton && event.KeyInput.Key == KEY_RETURN)
{
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if ((CancelButton || CloseButton) && event.KeyInput.Key == KEY_ESCAPE)
{
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (YesButton && event.KeyInput.Key == KEY_KEY_Y)
{
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (NoButton && event.KeyInput.Key == KEY_KEY_N)
{
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO;
Parent->OnEvent(outevent);
remove();
return true;
}
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{

View File

@ -46,6 +46,7 @@ namespace gui
s32 Flags;
core::stringw MessageText;
bool Pressed;
};
} // end namespace gui

View File

@ -22,6 +22,9 @@ CGUIModalScreen::CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* pare
setDebugName("CGUIModalScreen");
#endif
setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
// this element is a tab group
setTabGroup(true);
}
@ -36,6 +39,24 @@ bool CGUIModalScreen::OnEvent(SEvent event)
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUSED:
if (event.GUIEvent.Caller != this && !isMyChild(event.GUIEvent.Caller))
Environment->setFocus(this);
return false;
case EGET_ELEMENT_FOCUS_LOST:
if (!(isMyChild(event.GUIEvent.Element) || event.GUIEvent.Element == this))
{
MouseDownTime = os::Timer::getTime();
return true;
}
else
return IGUIElement::OnEvent(event);
break;
}
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
@ -44,22 +65,25 @@ bool CGUIModalScreen::OnEvent(SEvent event)
}
}
if (Parent)
Parent->OnEvent(event);
IGUIElement::OnEvent(event);
return true;
return true; // absorb everything
}
//! draws the element and its children
void CGUIModalScreen::draw()
{
IGUISkin *skin = Environment->getSkin();
if (!skin)
return;
u32 now = os::Timer::getTime();
if (now - MouseDownTime < 300 && (now / 70)%2)
{
core::list<IGUIElement*>::Iterator it = Children.begin();
core::rect<s32> r;
video::IVideoDriver* driver = Environment->getVideoDriver();
video::SColor c = Environment->getSkin()->getColor(gui::EGDC_3D_HIGH_LIGHT);
for (; it != Children.end(); ++it)
@ -70,7 +94,7 @@ void CGUIModalScreen::draw()
r.UpperLeftCorner.X -= 1;
r.UpperLeftCorner.Y -= 1;
driver->draw2DRectangle(c, r, &AbsoluteClippingRect);
skin->draw2DRectangle(this, c, r, &AbsoluteClippingRect);
}
}
@ -88,6 +112,13 @@ void CGUIModalScreen::removeChild(IGUIElement* child)
remove();
}
//! adds a child
void CGUIModalScreen::addChild(IGUIElement* child)
{
IGUIElement::addChild(child);
Environment->setFocus(child);
}
void CGUIModalScreen::updateAbsolutePosition()
{

View File

@ -28,6 +28,10 @@ namespace gui
//! Removes a child.
virtual void removeChild(IGUIElement* child);
//! Adds a child
virtual void addChild(IGUIElement* child);
//! draws the element and its children
virtual void draw();

View File

@ -32,6 +32,10 @@ CGUIScrollBar::CGUIScrollBar(bool horizontal, IGUIEnvironment* environment,
setNotClipped(noclip);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
setPos(0);
}
@ -52,6 +56,46 @@ bool CGUIScrollBar::OnEvent(SEvent event)
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
s32 oldPos = Pos;
bool absorb = true;
switch (event.KeyInput.Key)
{
case KEY_LEFT:
case KEY_UP:
setPos(Pos-SmallStep);
break;
case KEY_RIGHT:
case KEY_DOWN:
setPos(Pos+SmallStep);
break;
case KEY_HOME:
case KEY_PRIOR:
setPos(0);
break;
case KEY_END:
case KEY_NEXT:
setPos(Max);
break;
default:
absorb = false;
}
if (Pos != oldPos)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
}
if (absorb)
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{
@ -64,6 +108,7 @@ bool CGUIScrollBar::OnEvent(SEvent event)
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
@ -72,7 +117,7 @@ bool CGUIScrollBar::OnEvent(SEvent event)
else
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == (IGUIElement*)this)
if (event.GUIEvent.Caller == this)
Dragging = false;
}
break;
@ -86,6 +131,7 @@ bool CGUIScrollBar::OnEvent(SEvent event)
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
return true;
@ -121,6 +167,7 @@ bool CGUIScrollBar::OnEvent(SEvent event)
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
}
@ -130,7 +177,7 @@ bool CGUIScrollBar::OnEvent(SEvent event)
break;
}
return Parent ? Parent->OnEvent(event) : false;
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
@ -143,12 +190,10 @@ void CGUIScrollBar::draw()
if (!skin)
return;
irr::video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> rect = AbsoluteRect;
// draws the background
driver->draw2DRectangle(skin->getColor(EGDC_SCROLLBAR), rect, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), rect, &AbsoluteClippingRect);
if (Max!=0)
{
@ -305,6 +350,7 @@ void CGUIScrollBar::refreshControls()
{
UpButton = new CGUIButton(Environment, this, -1, core::rect<s32>(0,0, h, h), NoClip);
UpButton->setSubElement(true);
UpButton->setTabStop(false);
}
if (sprites)
{
@ -318,6 +364,7 @@ void CGUIScrollBar::refreshControls()
{
DownButton = new CGUIButton(Environment, this, -1, core::rect<s32>(RelativeRect.getWidth()-h, 0, RelativeRect.getWidth(), h), NoClip);
DownButton->setSubElement(true);
DownButton->setTabStop(false);
}
if (sprites)
{
@ -335,6 +382,7 @@ void CGUIScrollBar::refreshControls()
{
UpButton = new CGUIButton(Environment, this, -1, core::rect<s32>(0,0, w, w), NoClip);
UpButton->setSubElement(true);
UpButton->setTabStop(false);
}
if (sprites)
{
@ -348,6 +396,7 @@ void CGUIScrollBar::refreshControls()
{
DownButton = new CGUIButton(Environment, this, -1, core::rect<s32>(0,RelativeRect.getHeight()-w, w, RelativeRect.getHeight()), NoClip);
DownButton->setSubElement(true);
DownButton->setTabStop(false);
}
if (sprites)
{

View File

@ -770,6 +770,13 @@ EGUI_SKIN_TYPE CGUISkin::getType() const
return Type;
}
//! draws a 2d rectangle.
void CGUISkin::draw2DRectangle(IGUIElement* element, video::SColor &color, const core::rect<s32>& pos,
const core::rect<s32>* clip)
{
Driver->draw2DRectangle(color, pos, clip);
}
//! Writes attributes of the object.
//! Implement this to expose the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml serialization purposes.

View File

@ -189,6 +189,20 @@ namespace gui
const core::position2di position, u32 starttime=0, u32 currenttime=0,
bool loop=false, const core::rect<s32>* clip=0);
//! draws a 2d rectangle.
/** \param element: Pointer to the element which wishes to draw this icon.
This parameter is usually not used by IGUISkin, but can be used for example
by more complex implementations to find out how to draw the part exactly.
\param color: Color of the rectangle to draw. The alpha component specifies how
transparent the rectangle will be.
\param pos: Position of the rectangle.
\param clip: Pointer to rectangle against which the rectangle will be clipped.
If the pointer is null, no clipping will be performed. */
virtual void draw2DRectangle(IGUIElement* element, video::SColor &color,
const core::rect<s32>& pos, const core::rect<s32>* clip = 0);
//! get the type of this skin
virtual EGUI_SKIN_TYPE getType() const;

View File

@ -38,6 +38,7 @@ CGUISpinBox::CGUISpinBox(const wchar_t* text, IGUIEnvironment* environment,
rectangle.getWidth(), rectangle.getHeight()), this);
ButtonSpinDown->grab();
ButtonSpinDown->setSubElement(true);
ButtonSpinDown->setTabStop(false);
ButtonSpinDown->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_CENTER, EGUIA_LOWERRIGHT);
ButtonSpinUp = Environment->addButton(
@ -45,6 +46,7 @@ CGUISpinBox::CGUISpinBox(const wchar_t* text, IGUIEnvironment* environment,
rectangle.getWidth(), rectangle.getHeight()/2), this);
ButtonSpinUp->grab();
ButtonSpinUp->setSubElement(true);
ButtonSpinUp->setTabStop(false);
ButtonSpinUp->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_CENTER);
if (sb)
{
@ -67,8 +69,6 @@ CGUISpinBox::CGUISpinBox(const wchar_t* text, IGUIEnvironment* environment,
EditBox->grab();
EditBox->setSubElement(true);
EditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
// verifyValueRange();
}
//! destructor
@ -188,13 +188,15 @@ bool CGUISpinBox::OnEvent(SEvent event)
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
//fprintf(stderr, "EGET_SPINBOX_CHANGED caller:%p id: %d\n", e.GUIEvent.Caller, e.GUIEvent.Caller->getID() );
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_SPINBOX_CHANGED;
if ( Parent )
Parent->OnEvent(e);
return true;
}
return false;
return IGUIElement::OnEvent(event);
}
void CGUISpinBox::verifyValueRange()

View File

@ -61,10 +61,10 @@ void CGUITab::draw()
if (!IsVisible)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
IGUISkin *skin = Environment->getSkin();
if (DrawBackground)
driver->draw2DRectangle(BackColor, AbsoluteRect, &AbsoluteClippingRect);
if (skin && DrawBackground)
skin->draw2DRectangle(this, BackColor, AbsoluteRect, &AbsoluteClippingRect);
IGUIElement::draw();
}
@ -135,6 +135,9 @@ CGUITabControl::CGUITabControl(IGUIEnvironment* environment,
: IGUITabControl(environment, parent, id, rectangle), ActiveTab(-1),
Border(border), FillBackground(fillbackground)
{
#ifdef _DEBUG
setDebugName("CGUITabControl");
#endif
}
@ -240,14 +243,6 @@ bool CGUITabControl::OnEvent(SEvent event)
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case gui::EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == (IGUIElement*)this)
return true;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
@ -313,12 +308,11 @@ void CGUITabControl::draw()
return;
IGUIFont* font = skin->getFont();
video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> frameRect(AbsoluteRect);
if (Tabs.empty())
driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT),
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT),
frameRect, &AbsoluteClippingRect);
if (!font)
@ -382,11 +376,11 @@ void CGUITabControl::draw()
tr.LowerRightCorner.X = left - 1;
tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1;
tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y;
driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);
tr.UpperLeftCorner.X = right;
tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;
driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);
}
skin->draw3DTabBody(this, Border, FillBackground, AbsoluteRect, &AbsoluteClippingRect);
@ -429,6 +423,7 @@ bool CGUITabControl::setActiveTab(s32 idx)
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_TAB_CHANGED;
Parent->OnEvent(event);
}

View File

@ -42,6 +42,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close" );
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
if (sprites)
{
@ -55,6 +56,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id
L"", skin ? skin->getDefaultText(EGDT_WINDOW_RESTORE) : L"Restore" );
RestoreButton->setVisible(false);
RestoreButton->setSubElement(true);
RestoreButton->setTabStop(false);
RestoreButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
if (sprites)
{
@ -68,6 +70,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id
L"", skin ? skin->getDefaultText(EGDT_WINDOW_MINIMIZE) : L"Minimize" );
MinButton->setVisible(false);
MinButton->setSubElement(true);
MinButton->setTabStop(false);
MinButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
if (sprites)
{
@ -79,6 +82,11 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id
MinButton->grab();
RestoreButton->grab();
CloseButton->grab();
// this element is a tab group
setTabGroup(true);
setTabStop(true);
setTabOrder(-1);
}
@ -106,10 +114,14 @@ bool CGUIWindow::OnEvent(SEvent event)
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == (IGUIElement*)this)
Dragging = false;
}
else
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
{
if (event.GUIEvent.Caller == this && Parent)
{
Dragging = false;
return true;
Parent->bringToFront(this);
}
}
else
@ -128,9 +140,9 @@ bool CGUIWindow::OnEvent(SEvent event)
case EMIE_LMOUSE_PRESSED_DOWN:
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
Dragging = true;
if (!Environment->hasFocus(this))
{
Dragging = true;
Environment->setFocus(this);
if (Parent)
Parent->bringToFront(this);
@ -138,7 +150,6 @@ bool CGUIWindow::OnEvent(SEvent event)
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
Environment->removeFocus(this);
return true;
case EMIE_MOUSE_MOVED:
if (Dragging)
@ -162,7 +173,7 @@ bool CGUIWindow::OnEvent(SEvent event)
}
}
return Parent ? Parent->OnEvent(event) : false;
return IGUIElement::OnEvent(event);
}
//! Updates the absolute position.

View File

@ -732,6 +732,10 @@
RelativePath=".\..\..\include\EGUIElementTypes.h"
>
</File>
<File
RelativePath="..\..\include\EMessageBoxFlags.h"
>
</File>
<File
RelativePath=".\..\..\include\ICursorControl.h"
>

View File

@ -64,12 +64,15 @@ namespace gui
switch (e.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUSED:
if (Parent)
if (Parent && isMyChild(e.GUIEvent.Caller))
Parent->bringToFront(this);
break;
case EGET_ELEMENT_HOVERED:
case EGET_ELEMENT_LEFT:
return true;
return IGUIElement::OnEvent(e);
case EGET_ELEMENT_FOCUS_LOST:
updateAttrib();
return IGUIElement::OnEvent(e);
default:
return updateAttrib();
}

View File

@ -29,6 +29,9 @@ CGUIAttributeEditor::CGUIAttributeEditor(IGUIEnvironment* environment, s32 id, I
// create attributes
Attribs = environment->getFileSystem()->createEmptyAttributes(Environment->getVideoDriver());
calculateClientArea();
resizeInnerPane();
// refresh attrib list
refreshAttribs();
@ -72,7 +75,7 @@ void CGUIAttributeEditor::refreshAttribs()
position2di top(10, 5);
rect<s32> r(top.X,
top.Y,
AbsoluteRect.getWidth() - 10,
getClientArea().getWidth() - 10,
5 + Environment->getSkin()->getFont()->getDimension(L"A").Height);
// add attribute elements

View File

@ -108,9 +108,8 @@ namespace gui
AttribSliderR->setPos(col.getRed());
AttribSliderG->setPos(col.getGreen());
AttribSliderB->setPos(col.getBlue());
return updateAttrib();
}
break;
case EGET_SCROLL_BAR_CHANGED:
{
// update editbox from scrollbars

View File

@ -23,6 +23,13 @@ CGUIEditWindow::CGUIEditWindow(IGUIEnvironment* environment, core::rect<s32> rec
setDebugName("CGUIEditWindow");
#endif
// we can't tab out of this window
setTabGroup(true);
// we can ctrl+tab to it
setTabStop(true);
// the tab order number is auto-assigned
setTabOrder(-1);
// set window text
setText(L"GUI Editor");
@ -177,13 +184,12 @@ bool CGUIEditWindow::OnEvent(SEvent event)
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
Dragging = false;
Resizing = false;
return true;
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == this ||
event.GUIEvent.Caller == ResizeButton)
{
Dragging = false;
Resizing = false;
}
break;
}
@ -202,7 +208,7 @@ bool CGUIEditWindow::OnEvent(SEvent event)
if (clickedElement == this)
{
Dragging = true;
Environment->setFocus(this);
//Environment->setFocus(this);
if (Parent)
Parent->bringToFront(this);
return true;
@ -210,7 +216,7 @@ bool CGUIEditWindow::OnEvent(SEvent event)
else if (clickedElement == ResizeButton)
{
Resizing = true;
Environment->setFocus(this);
//Environment->setFocus(this);
if (Parent)
Parent->bringToFront(this);
return true;
@ -221,7 +227,7 @@ bool CGUIEditWindow::OnEvent(SEvent event)
if (Dragging || Resizing)
{
Dragging = false;
Environment->removeFocus(this);
Resizing = false;
return true;
}
break;

View File

@ -143,22 +143,6 @@ IGUIElement* CGUIEditWorkspace::getEditableElementFromPoint(IGUIElement *start,
return target;
}
bool CGUIEditWorkspace::isMyChild(IGUIElement* target)
{
if (!target)
return false;
IGUIElement *current = target;
while(current->getParent())
{
current = current->getParent();
if (current == this)
return true;
}
return false;
}
void CGUIEditWorkspace::setSelectedElement(IGUIElement *sel)
{
IGUIElement* focus = Environment->getFocus();
@ -700,8 +684,9 @@ bool CGUIEditWorkspace::OnEvent(SEvent e)
break;
}
// even if we didn't absorb the event,
// we never pass events back to the GUI we're editing!
return true;
return false;
}

View File

@ -89,8 +89,6 @@ namespace gui
private:
bool isMyChild(IGUIElement* target);
enum EGUIEDIT_MODE
{
// when we are currently selecting an element

View File

@ -38,6 +38,7 @@ CGUIPanel::CGUIPanel( IGUIEnvironment* environment, IGUIElement* parent, s32 id,
VScrollBar = environment->addScrollBar( false, rct, 0, id );
VScrollBar->setSubElement(true);
VScrollBar->setTabStop(false);
VScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
VScrollBar->grab();
IGUIElement::addChild(VScrollBar);
@ -46,6 +47,7 @@ CGUIPanel::CGUIPanel( IGUIEnvironment* environment, IGUIElement* parent, s32 id,
HScrollBar = environment->addScrollBar( true, rct, 0, id );
HScrollBar->setSubElement(true);
HScrollBar->setTabStop(false);
HScrollBar->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
HScrollBar->grab();
IGUIElement::addChild(HScrollBar);
@ -181,7 +183,6 @@ bool CGUIPanel::OnEvent( SEvent event )
HScrollBar->OnEvent(event);
return true;
}
return false;
}
else
{
@ -192,11 +193,9 @@ bool CGUIPanel::OnEvent( SEvent event )
return true;
}
else
return IGUIElement::OnEvent( event );
}
return false;
return IGUIElement::OnEvent(event);
}
void CGUIPanel::moveInnerPane()

View File

@ -216,7 +216,7 @@ bool CGUITextureCacheBrowser::OnEvent(SEvent event)
if (!Environment->hasFocus(this))
{
Dragging = true;
Environment->setFocus(this);
//Environment->setFocus(this);
if (Parent)
Parent->bringToFront(this);
}
@ -244,7 +244,7 @@ bool CGUITextureCacheBrowser::OnEvent(SEvent event)
break;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
Environment->removeFocus(this);
//Environment->removeFocus(this);
return true;
case EMIE_MOUSE_MOVED:
if (Dragging)