diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/EAttributes.h Irrlicht_starsonata/include/EAttributes.h --- irrlicht-svn-ss/trunk/include/EAttributes.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/EAttributes.h 2007-10-22 18:57:04.000000000 +0200 @@ -0,0 +1,114 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_ATTRIBUTES_H_INCLUDED__ +#define __E_ATTRIBUTES_H_INCLUDED__ + +namespace irr +{ + +namespace io +{ + +//! Types of attributes available for IAttributes +enum E_ATTRIBUTE_TYPE +{ + // integer attribute + EAT_INT = 0, + + // float attribute + EAT_FLOAT, + + // string attribute + EAT_STRING, + + // boolean attribute + EAT_BOOL, + + // enumeration attribute + EAT_ENUM, + + // color attribute + EAT_COLOR, + + // floating point color attribute + EAT_COLORF, + + // 3d vector attribute + EAT_VECTOR3D, + + // 2d position attribute + EAT_POSITION2D, + + // vector 2d + EAT_VECTOR2D, + + // rectangle attribute + EAT_RECT, + + // matrix attribute + EAT_MATRIX, + + // quaternion attribute + EAT_QUATERNION, + + // 3d bounding box + EAT_BBOX, + + // plane + EAT_PLANE, + + // 3d triangle + EAT_TRIANGLE3D, + + // line 2d + EAT_LINE2D, + + // line 3d + EAT_LINE3D, + + // array of stringws attribute + EAT_STRINGWARRAY, + + // array of float + EAT_FLOATARRAY, + + // array of int + EAT_INTARRAY, + + // binary data attribute + EAT_BINARY, + + // texture reference attribute + EAT_TEXTURE, + + // user pointer void* + EAT_USER_POINTER, + + // known attribute type count + EAT_COUNT, + + // unknown attribute + EAT_UNKNOWN +}; + +//! usage for default attributes +enum E_DEFAULT_ATTRIBUTE_USAGE +{ + //! do not use default attributes + EDAU_IGNORE, + + //! use default attributes on reading when no other attribute with that name exists + EDAU_READ_ONLY, + + //! do not write attributes if a default attribute with the same name does exist + EDAU_WRITE_ONLY, + + //! like EDAU_READ_ONLY and EDAU_WRITE_ONLY combined + EDAU_READ_WRITE, +}; + +} // end namespace io +} // end namespace irr + +#endif // __E_ATTRIBUTES_H_INCLUDED__ diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/EGUIElementTypes.h Irrlicht_starsonata/include/EGUIElementTypes.h --- irrlicht-svn-ss/trunk/include/EGUIElementTypes.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/EGUIElementTypes.h 2007-10-22 18:57:04.000000000 +0200 @@ -77,6 +77,12 @@ enum EGUI_ELEMENT_TYPE //! A spin box (IGUISpinBox) EGUIET_SPIN_BOX, + //! A table (IGUITable) + EGUIET_TABLE, + + //! A colored rectangle (IGUIRectangle) + EGUIET_RECTANGLE, + //! Not an element, amount of elements in there EGUIET_COUNT, @@ -113,7 +119,10 @@ const c8* const GUIElementTypeNames[] = "toolBar", "window", "spinBox", - 0 + "table", + "rectangle", + 0, // count + "unknown" }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/EWindowFlags.h Irrlicht_starsonata/include/EWindowFlags.h --- irrlicht-svn-ss/trunk/include/EWindowFlags.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/EWindowFlags.h 2008-05-31 04:15:24.000000000 +0200 @@ -0,0 +1,30 @@ +// Copyright (C) 2007 StarSonata + +#ifndef __E_WINDOW_FLAGS_H_INCLUDED__ +#define __E_WINDOW_FLAGS_H_INCLUDED__ + +namespace irr +{ +namespace gui +{ + + //! enumeration for windows layout flags + enum EWINDOW_FLAG + { + //! Flag for close button + EWF_CLOSE = 0x1, + + //! Flag for title bar of windows + EWF_TITLEBAR = 0x2, + + //! Flag for maximize button + EWF_MAXIMIZE = 0x4, + + //! Flag for minimize button + EWF_MINIMIZE = 0x8, + }; + +} // namespace gui +} // namespace irr + +#endif diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/Extended_IGUIRectangle.h Irrlicht_starsonata/include/Extended_IGUIRectangle.h --- irrlicht-svn-ss/trunk/include/Extended_IGUIRectangle.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/Extended_IGUIRectangle.h 2007-10-22 18:57:04.000000000 +0200 @@ -0,0 +1,32 @@ +#ifndef __EXTENDED_IGUIRECTANGLE_H__ +#define __EXTENDED_IGUIRECTANGLE_H__ + +#include "IGUIElement.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + + //! A rectangle displaying smoothly interpolated colors which can be set for each corner + class IGUIRectangle : public IGUIElement + { + public: + + //! constructor + IGUIRectangle(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_RECTANGLE, environment, parent, id, rectangle) {} + + // Set the colors of the four corners of the rectangle + virtual void setCornerColors(video::SColor colorLeftUp, video::SColor colorRightUp, video::SColor colorLeftDown, video::SColor colorRightDown) = 0; + + //! destructor + ~IGUIRectangle() {}; + }; + + +} // end namespace gui +} // end namespace irr + +#endif diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/heapsort.h Irrlicht_starsonata/include/heapsort.h --- irrlicht-svn-ss/trunk/include/heapsort.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/heapsort.h 2008-06-07 13:56:26.000000000 +0200 @@ -12,6 +12,72 @@ namespace irr namespace core { +//! Function object which can be used for sorting +template +bool Less(const T& a, const T& b) +{ + return a < b; +} + +//! Function object which can be used for sorting +template +bool Greater(const T& a, const T& b) +{ + return a > b; +} + +//! Sinks an element into the heap with a custom compare function +template +inline void heapsink(T*array, s32 element, s32 max, Compare cmp) +{ + while ((element<<1) < max) // there is a left child + { + s32 j = (element<<1); + + if (j+1 < max && cmp(array[j],array[j+1]) ) + j = j+1; // take right child + + if ( cmp( array[element], array[j]) ) + { + T t = array[j]; // swap elements + array[j] = array[element]; + array[element] = t; + element = j; + } + else + return; + } +} + + +//! Sorts an array with size 'size' using heapsort with a custom compare function +template +inline void heapsort(T* array_, s32 size, Compare cmp) +{ + // for heapsink we pretent this is not c++, where + // arrays start with index 0. So we decrease the array pointer, + // the maximum always +2 and the element always +1 + + T* virtualArray = array_ - 1; + s32 virtualSize = size + 2; + s32 i; + + // build heap + + for (i=((size-1)/2); i>=0; --i) + heapsink(virtualArray, i+1, virtualSize-1, cmp); + + // sort array + + for (i=size-1; i>=0; --i) + { + T t = array_[0]; + array_[0] = array_[i]; + array_[i] = t; + heapsink(virtualArray, 1, i + 1, cmp); + } +} + //! Sinks an element into the heap. template inline void heapsink(T*array, s32 element, s32 max) @@ -68,6 +134,5 @@ inline void heapsort(T* array_, s32 size } // end namespace irr - #endif diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IAttributes.h Irrlicht_starsonata/include/IAttributes.h --- irrlicht-svn-ss/trunk/include/IAttributes.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IAttributes.h 2007-12-28 23:37:02.000000000 +0100 @@ -23,6 +23,7 @@ #include "irrString.h" #include "irrArray.h" #include "IXMLReader.h" +#include "EAttributes.h" namespace irr { @@ -34,93 +35,91 @@ namespace io { class IXMLWriter; -//! Types of attributes available for IAttributes -enum E_ATTRIBUTE_TYPE +class IAttribute : public virtual IUnknown { - // integer attribute - EAT_INT = 0, - - // float attribute - EAT_FLOAT, - - // string attribute - EAT_STRING, - - // boolean attribute - EAT_BOOL, - - // enumeration attribute - EAT_ENUM, - - // color attribute - EAT_COLOR, - - // floating point color attribute - EAT_COLORF, - - // 3d vector attribute - EAT_VECTOR3D, - - // 2d position attribute - EAT_POSITION2D, - - // vector 2d - EAT_VECTOR2D, - - // rectangle attribute - EAT_RECT, - - // matrix attribute - EAT_MATRIX, - - // quaternion attribute - EAT_QUATERNION, - - // 3d bounding box - EAT_BBOX, - - // plane - EAT_PLANE, - - // 3d triangle - EAT_TRIANGLE3D, - - // line 2d - EAT_LINE2D, - - // line 3d - EAT_LINE3D, +public: - // array of stringws attribute - EAT_STRINGWARRAY, + virtual ~IAttribute() {}; - // array of float - EAT_FLOATARRAY, + virtual bool isEqualTo(IAttribute* attrib) { return attrib ? (getStringW() == attrib->getStringW()) && (getType()==attrib->getType()) : false; } - // array of int - EAT_INTARRAY, + virtual s32 getInt() { return 0; } + virtual f32 getFloat() { return 0; } + virtual video::SColorf getColorf() { return video::SColorf(1.0f,1.0f,1.0f,1.0f); } + virtual video::SColor getColor() { return video::SColor(255,255,255,255); } + virtual core::stringc getString() { return core::stringc(getStringW().c_str()); } + virtual core::stringw getStringW() { return core::stringw(); } + virtual core::array getArray() { return core::array(); }; + virtual bool getBool() { return false; } + virtual void getBinary(void* outdata, s32 maxLength) {}; + virtual core::vector3df getVector() { return core::vector3df(); } + virtual core::position2di getPosition() { return core::position2di(); } + virtual core::rect getRect() { return core::rect(); } + virtual core::quaternion getQuaternion(){ return core::quaternion(); } + virtual core::matrix4 getMatrix() { return core::matrix4(); } + virtual core::triangle3df getTriangle() { return core::triangle3df(); } + virtual core::vector2df getVector2d() { return core::vector2df(); } + virtual core::vector2di getVector2di() { return core::vector2di(); } + virtual core::line2df getLine2d() { return core::line2df(); } + virtual core::line2di getLine2di() { return core::line2di(); } + virtual core::line3df getLine3d() { return core::line3df(); } + virtual core::line3di getLine3di() { return core::line3di(); } + virtual core::dimension2di getDimension2d() { return core::dimension2di(); } + virtual core::aabbox3d getBBox() { return core::aabbox3d(); } + virtual core::plane3df getPlane() { return core::plane3df(); } - // binary data attribute - EAT_BINARY, + virtual video::ITexture* getTexture() { return 0; } + virtual const char* getEnum() { return 0; } + virtual void* getUserPointer() { return 0; } - // texture reference attribute - EAT_TEXTURE, + virtual void setInt(s32 intValue) {}; + virtual void setFloat(f32 floatValue) {}; + virtual void setString(const char* text) {}; + virtual void setString(const wchar_t* text){ setString(core::stringc(text).c_str()); }; + virtual void setArray( core::array arr ) {}; + virtual void setColor(video::SColorf color) {}; + virtual void setColor(video::SColor color) {}; + virtual void setBool(bool boolValue) {}; + virtual void setBinary(void* data, s32 maxLenght) {}; + virtual void setVector(core::vector3df v) {}; + virtual void setPosition(core::position2di v) {}; + virtual void setRect(core::rect v) {}; + virtual void setQuaternion(core::quaternion v) {}; + virtual void setMatrix(core::matrix4 v) {}; + virtual void setTriangle(core::triangle3df v) {}; + virtual void setVector2d(core::vector2df v) {}; + virtual void setVector2d(core::vector2di v) {}; + virtual void setLine2d(core::line2df v) {}; + virtual void setLine2d(core::line2di v) {}; + virtual void setLine3d(core::line3df v) {}; + virtual void setLine3d(core::line3di v) {}; + virtual void setDimension2d(core::dimension2di v) {}; + virtual void setBBox(core::aabbox3d v) {}; + virtual void setPlane(core::plane3df v) {}; + virtual void setUserPointer(void* v) {}; - // user pointer void* - EAT_USER_POINTER, + virtual void setEnum(const char* enumValue, const char* const* enumerationLiterals) {}; + virtual void setTexture(video::ITexture*) {}; - // known attribute type count - EAT_COUNT, + core::stringc Name; - // unknown attribute - EAT_UNKNOWN + virtual E_ATTRIBUTE_TYPE getType() const = 0; + virtual const wchar_t* getTypeString() const = 0; }; + //! Provides a generic interface for attributes and their values and the possiblity to serialize them class IAttributes : public virtual IUnknown { public: + //! Default attribute values are returned as result when usual attributnames are not found + virtual void setDefaultAttributes(IAttributes * attrib) = 0; + virtual IAttributes * getDefaultAttributes() = 0; + + // set in which situations default attributes should be used. + virtual void setDefaultAttributeUsage(E_DEFAULT_ATTRIBUTE_USAGE usage) = 0; + //! Returns amount of attributes in this collection of attributes. virtual s32 getAttributeCount() = 0; @@ -740,6 +739,8 @@ public: //! Sets an attribute as user pointer virtual void setAttribute(s32 index, void* userPointer) = 0; + //! get attribute by name + virtual IAttribute* getAttributeP(const c8* attributeName) = 0; }; } // end namespace io diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IEventReceiver.h Irrlicht_starsonata/include/IEventReceiver.h --- irrlicht-svn-ss/trunk/include/IEventReceiver.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IEventReceiver.h 2008-06-07 11:17:50.000000000 +0200 @@ -59,6 +59,12 @@ namespace irr //! in what direction and how fast. EMIE_MOUSE_WHEEL, + // Starsonata, Micha: Only implemented for windows so far + //! double click events (additional to and before the second EMIE_?MOUSE_UP events) + EMIE_LMOUSE_DOUBLE_CLICK, + EMIE_RMOUSE_DOUBLE_CLICK, + EMIE_MMOUSE_DOUBLE_CLICK, + //! No real event. Just for convenience to get number of events EMIE_COUNT }; @@ -84,9 +90,17 @@ namespace irr //! A hovered gui element was left EGET_ELEMENT_LEFT, + //! An element would like to close. + //! Windows and context menus use this event when they would like to close, + //! this can be cancelled by absorbing the event. + EGET_ELEMENT_CLOSED, + //! A button was clicked. EGET_BUTTON_CLICKED, + //! The pressed state of a pushbutton was changed + EGET_PUSHBUTTON_STATE_CHANGED, + //! A scrollbar has changed its position. EGET_SCROLL_BAR_CHANGED, @@ -99,6 +113,17 @@ namespace irr //! An item in the listbox was selected, which was already selected. EGET_LISTBOX_SELECTED_AGAIN, + //! A new row in the table was selected. + EGET_TABLE_CHANGED, + + //! A row in the table was selected, which was already selected. + EGET_TABLE_SELECTED_AGAIN, + + //! An element got double-clicked + //! Not all elements will transport this, but usually only element for which + //! double-clicking is typically used to trigger certain actions + EGET_ELEMENT_DOUBLE_CLICKED, + //! A file has been selected in the file dialog EGET_FILE_SELECTED, @@ -120,18 +145,44 @@ namespace irr //! In an editbox was pressed 'ENTER' EGET_EDITBOX_ENTER, + //! In an editbox the text was changed. + // ! Could be because the user pressed keys, but also when the text is changed manually. + EGET_EDITBOX_TEXT_CHANGED, + //! The tab was changed in an tab control EGET_TAB_CHANGED, + //! The table header was changed in a table control + EGET_TABLE_HEADER_CHANGED, + //! A menu item was selected in a (context) menu EGET_MENU_ITEM_SELECTED, //! The selection in a combo box has been changed EGET_COMBO_BOX_CHANGED, + //! A gui element has gained focus. + EGET_ELEMENT_FOCUS_GAINED, + + //! A gui element has gained focus and is telling others. + EGET_MESSAGE_FOCUS_LOST, + + //! A gui element has gained focus and is telling others. + EGET_MESSAGE_FOCUS_GAINED, + + //! A window has been closed. + EGET_WINDOW_CLOSED, + + //! A window is resized by the user + //! The sizing rect can be accessed and change by IGUIWindow::getSizingRect() + //! Also resizing can be prevented by returning true for the event. + EGET_WINDOW_SIZING, + //! The value of a spin box has changed - EGET_SPINBOX_CHANGED + EGET_SPINBOX_CHANGED, + //! No real event. Just for convenience to get number of events + EGET_COUNT }; } // end namespace gui @@ -168,6 +219,12 @@ struct SEvent /** Only valid if event was EMIE_MOUSE_WHEEL */ f32 Wheel; + //! true if shift was also pressed + bool Shift; + + //! true if ctrl was also pressed + bool Control; + //! type of mouse event EMOUSE_INPUT_EVENT Event; } MouseInput; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIButton.h Irrlicht_starsonata/include/IGUIButton.h --- irrlicht-svn-ss/trunk/include/IGUIButton.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIButton.h 2008-03-20 04:50:48.000000000 +0100 @@ -68,6 +68,10 @@ namespace gui \param font: New font to set. */ virtual void setOverrideFont(IGUIFont* font=0) = 0; + // Starsonata, Micha + //! Return the font which is used for this button + virtual IGUIFont* getCurrentFont() = 0; + //! Sets an image which should be displayed on the button when it is in normal state. /** \param image: Image to be displayed */ virtual void setImage(video::ITexture* image) = 0; @@ -88,6 +92,15 @@ namespace gui \param pos: Position in the texture, where the image is located */ virtual void setPressedImage(video::ITexture* image, const core::rect& pos) = 0; + //! Sets the background image which should be displayed on the button when it is in disabled state. + /** \param image: Image to be displayed */ + virtual void setDisabledImage(video::ITexture* image) = 0; + + //! Sets the background image which should be displayed on the button when it is in disabled state. + /** \param image: Texture containing the image to be displayed + \param pos: Position in the texture, where the image is located */ + virtual void setDisabledImage(video::ITexture* image, const core::rect& pos) = 0; + //! Sets the sprite bank used by the button virtual void setSpriteBank(IGUISpriteBank* bank) = 0; @@ -107,6 +120,7 @@ namespace gui virtual void setIsPushButton(bool isPushButton) = 0; //! Sets the pressed state of the button if this is a pushbutton + //! This will not cause EGET_PUSHBUTTON_STATE_CHANGED events virtual void setPressed(bool pressed) = 0; //! Returns if the button is currently pressed @@ -126,6 +140,31 @@ namespace gui //! Returns if the border and button face are being drawn using the skin virtual bool isDrawingBorder() = 0; + + // starsonata, micha: flashing background + //! enabled/disable flashing of the button background + virtual void setFlashing(bool flash_) = 0; + + // starsonata, micha: flashing background + //! is the button background flashing + virtual bool isFlashing() const = 0; + + // starsonata, micha: flashing background + //! get the state of the shift key when the last click event was created + virtual bool getClickShiftState() const = 0; + + // starsonata, micha: flashing background + //! get the state of the control key when the last click event was created + virtual bool getClickControlState() const = 0; + + // starsonata, micha: override the usual text color + //! set a new textcolor which can override the default from the skin + //! the override color will only be used if enableOverrideTextColor is set to true + virtual void setOverrideTextColor( video::SColor color=video::SColor(255,255,255,255) ) = 0; + + // starsonata, micha: override the usual text color + //! use the color from setOverrideTextColor instead of the skin color + virtual void enableOverrideTextColor(bool enable) = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUICheckBox.h Irrlicht_starsonata/include/IGUICheckBox.h --- irrlicht-svn-ss/trunk/include/IGUICheckBox.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUICheckBox.h 2008-04-25 22:50:44.000000000 +0200 @@ -11,7 +11,6 @@ namespace irr { namespace gui { - //! GUI Check box interface. class IGUICheckBox : public IGUIElement { @@ -29,6 +28,19 @@ namespace gui //! Returns true if box is checked. virtual bool isChecked() = 0; + + // starsonata, micha - adding spritesupport to have more layout possibilities + //! Set the spritebank which will be used to draw custom icons. + virtual void setSpriteBank(const c8 *bankName) = 0; + + // starsonata, micha - adding spritesupport to have more layout possibilities + //! Set a sprite which will be used for drawing in "checked" state + //! Set the spritebank for this in setSpriteBank, otherwise the spritebank of the default skin is used + virtual void setIconChecked(s32 spriteIdx) = 0; + + //! set a sprite which will be used for drawing in "unchecked" state + //! Set the spritebank for this in setSpriteBank, otherwise the spritebank of the default skin is used + virtual void setIconUnChecked(s32 spriteIdx) = 0; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIComboBox.h Irrlicht_starsonata/include/IGUIComboBox.h --- irrlicht-svn-ss/trunk/include/IGUIComboBox.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIComboBox.h 2007-12-28 05:45:50.000000000 +0100 @@ -45,6 +45,11 @@ namespace gui //! Sets the selected item. Set this to -1 if no item should be selected virtual void setSelected(s32 id) = 0; + //! set the custom data field for the item + virtual void setItemData(s32 idx, void *data) = 0; + + //! get the custom data field for the item + virtual void* getItemData(s32 idx) const = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIContextMenu.h Irrlicht_starsonata/include/IGUIContextMenu.h --- irrlicht-svn-ss/trunk/include/IGUIContextMenu.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIContextMenu.h 2008-06-06 07:41:40.000000000 +0200 @@ -11,6 +11,24 @@ namespace irr { namespace gui { + // starsonata, micha (removing menus would conflict with sane event handling, as ID's would have to be saved extra otherwise) + //! close behaviour + //! flags can be combined, but that will make only sense in extreme cases where you know what you do. + //! default is ECMC_REMOVE + enum ECONTEXT_MENU_CLOSE + { + //! do nothing - menu stays open + ECMC_IGNORE = 0, + + //! remove the gui element + ECMC_REMOVE = 1, + + //! drop the gui element + ECMC_DROP = 2, + + //! call setVisible(false) + ECMC_HIDE = 4, + }; //! GUI Context menu interface. class IGUIContextMenu : public IGUIElement @@ -40,7 +58,7 @@ namespace gui \return Returns the index of the new item */ virtual s32 addItem(const wchar_t* text, s32 commandId=-1, bool enabled=true, bool hasSubMenu=false, - bool checked=false + bool checked=false, bool autoChecking=false ) = 0; //! Adds a separator item to the menu @@ -55,6 +73,10 @@ namespace gui \param text: New text of the item. */ virtual void setItemText(s32 idx, const wchar_t* text) = 0; + //! Starsonata, MICHA: textID for stringtables + virtual const wchar_t* getItemTextID(s32 idx) = 0; + virtual void setItemTextID(s32 idx, const wchar_t* text) = 0; + //! Check if a menu item is enabled /** \param idx: Zero based index of the menu item */ virtual bool isItemEnabled(s32 idx) = 0; @@ -94,11 +116,38 @@ namespace gui set to whatever you want. */ virtual void setItemCommandId(s32 idx, s32 id) = 0; + // starsonata, micha - a useful comfort function + //! Find a item which has the given CommandId starting from given index (or idxStartSearch=0 for searching from start) + //! return -1 if no such item was found + virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch=0) = 0; + //! Get a pointer to the submenu of an item. /** 0 is returned if there is no submenu \param idx: Zero based index of the menu item \return Returns a pointer to the submenu of an item. */ virtual IGUIContextMenu* getSubMenu(s32 idx) = 0; + + // starsonata, micha - just removing won't always work + //! set behaviour when menus are closed + virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose) = 0; + + //! get current behaviour when the menue will be closed + virtual ECONTEXT_MENU_CLOSE getCloseHandling() const = 0; + + // starsonata, micha - grownup menues can handle checking flags themself + //! should the element change the checked status on clicking + virtual void setItemAutoChecking(s32 idx, bool autoChecking) = 0; + + //! does the element change the checked status on clicking + virtual bool getItemAutoChecking(s32 idx) = 0; + + // starsonata, micha + //! Make sure to show it at a good place around the given coordinates. + //! A comfort function which can for example be used after right-clicks with the mouse coordinates. + virtual void popupAt(irr::s32 x_, irr::s32 y_) = 0; + + // Starsonata, Micha, this was protected formerly, but it's rather useful as general functions for popups + virtual void setEventParent(IGUIElement *parent) = 0; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIEditBox.h Irrlicht_starsonata/include/IGUIEditBox.h --- irrlicht-svn-ss/trunk/include/IGUIEditBox.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIEditBox.h 2008-02-21 23:27:30.000000000 +0100 @@ -95,6 +95,10 @@ namespace gui //! Returns maximum amount of characters, previously set by setMax(); virtual s32 getMax() = 0; + + virtual void setPasswordField( bool isPasswordField ) = 0; + + virtual void setCursorPosition( u32 pos ) = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIElementFactory.h Irrlicht_starsonata/include/IGUIElementFactory.h --- irrlicht-svn-ss/trunk/include/IGUIElementFactory.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIElementFactory.h 2007-10-22 18:57:04.000000000 +0200 @@ -57,6 +57,9 @@ namespace gui /** \param type: Type of GUI element. \return: Returns name of the type if this factory can create the type, otherwise 0. */ virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) = 0; + + //! get the typenumber for the elementname + virtual EGUI_ELEMENT_TYPE getTypeFromName(const c8* name) = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIElement.h Irrlicht_starsonata/include/IGUIElement.h --- irrlicht-svn-ss/trunk/include/IGUIElement.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIElement.h 2008-07-25 16:36:24.000000000 +0200 @@ -228,11 +228,8 @@ public: if (NoClip) { IGUIElement* p=this; - while (p && p->NoClip && p->Parent) + while (p && p->Parent) p = p->Parent; - if (p->Parent) - parentAbsoluteClip = p->Parent->AbsoluteClippingRect; - else parentAbsoluteClip = p->AbsoluteClippingRect; } else @@ -446,6 +443,83 @@ public: setRelativePosition(DesiredRect + absoluteMovement); } + // starsonata, micha + //! Try to move the element as good as possible inside the given absolute coordinates. + //! When it does not fit inside try to align it as good as possible + virtual void moveInside(const core::rect& absRect, EGUI_ALIGNMENT align_=EGUIA_CENTER) + { + core::rect desired(AbsoluteRect); + if (! desired.constrainTo(absRect) ) + { + switch ( align_ ) + { + case EGUIA_UPPERLEFT: + { + core::position2d out; + if ( desired.UpperLeftCorner.X < absRect.UpperLeftCorner.X ) + { + out.X = desired.UpperLeftCorner.X - absRect.UpperLeftCorner.X; + } + if ( desired.UpperLeftCorner.Y < absRect.UpperLeftCorner.Y ) + { + out.Y = desired.UpperLeftCorner.Y - absRect.UpperLeftCorner.Y; + } + desired -= out; + } + break; + case EGUIA_LOWERRIGHT: + { + core::position2d out; + if ( desired.LowerRightCorner.X > absRect.LowerRightCorner.X ) + { + out.X = desired.LowerRightCorner.X - absRect.LowerRightCorner.X; + } + if ( desired.LowerRightCorner.Y > absRect.LowerRightCorner.Y ) + { + out.Y = desired.LowerRightCorner.Y - absRect.LowerRightCorner.Y; + } + desired -= out; + } + break; + case EGUIA_CENTER: + { + core::position2d toMove; + core::position2d centerDesired( desired.getCenter() ); + core::position2d centerAbs( absRect.getCenter() ); + + if ( desired.getWidth() > absRect.getWidth() ) + toMove.X = centerAbs.X - centerDesired.X; + else if ( desired.UpperLeftCorner.X < absRect.UpperLeftCorner.X ) + toMove.X = absRect.UpperLeftCorner.X - desired.UpperLeftCorner.X; + else if ( desired.LowerRightCorner.X > absRect.LowerRightCorner.X ) + toMove.X = absRect.LowerRightCorner.X - desired.LowerRightCorner.X; + + if ( desired.getHeight() > absRect.getHeight() ) + toMove.Y = centerAbs.Y - centerDesired.Y; + else if ( desired.UpperLeftCorner.Y < absRect.UpperLeftCorner.Y ) + toMove.Y = absRect.UpperLeftCorner.Y - desired.UpperLeftCorner.Y; + else if ( desired.LowerRightCorner.Y > absRect.LowerRightCorner.Y ) + toMove.Y = absRect.LowerRightCorner.Y - desired.LowerRightCorner.Y; + + desired += toMove; + } + break; + case EGUIA_SCALE: + { + f32 scaleX = desired.getWidth() ? (f32)absRect.getWidth() / (f32)desired.getWidth() : 0; + f32 scaleY = desired.getHeight() ? (f32)absRect.getHeight() / (f32)desired.getHeight() : 0; + f32 smallerScale = scaleX > scaleY ? scaleX : scaleY; + desired.LowerRightCorner.X = desired.UpperLeftCorner.X + (s32)(desired.getWidth() * smallerScale); + desired.LowerRightCorner.Y = desired.UpperLeftCorner.Y + (s32)(desired.getHeight() * smallerScale); + moveInside(absRect, EGUIA_CENTER); + return; + } + break; + } + } + + move( desired.UpperLeftCorner-AbsoluteRect.UpperLeftCorner ); + } //! Returns true if element is visible. virtual bool isVisible() @@ -636,6 +710,20 @@ public: return false; } + // Added by StarSonata, Micha + //! this will not just bringToFront this element, but also all it's parents. + virtual void bringToTop() + { + IGUIElement * parentElement = getParent(); + IGUIElement * childElement = this; + while ( parentElement ) + { + parentElement->bringToFront( childElement ); + childElement = parentElement; + parentElement = parentElement->getParent(); + } + } + //! Returns list with children of this element virtual const core::list& getChildren() const { @@ -786,11 +874,32 @@ public: return GUIElementTypeNames[Type]; } + //! STARSONATA, MICHA: Access the element name + core::stringc & getName() + { + return Name; + } + + //! Starsonata, MICHA: textID for stringtables + virtual void setTextID(const wchar_t* text) + { + TextID = text; + } + + //! Returns caption of this element. + virtual const wchar_t* getTextID() + { + return TextID.c_str(); + } + + //! Writes attributes of the scene node. //! Implement this to expose the attributes of your scene node for //! scripting languages, editors, debuggers or xml serialization purposes. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) { + out->addString("IdName", Name.c_str() ); // call it IdName instead of name, because otherwise it's hard to find in the xml + out->addString("TextID", getTextID()); out->addInt("Id", ID ); out->addString("Caption", getText()); out->addRect("Rect", DesiredRect); @@ -813,13 +922,15 @@ public: //! scripting languages, editors, debuggers or xml deserialization purposes. virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { + Name = in->getAttributeAsString("IdName"); + setTextID(in->getAttributeAsStringW("TextID").c_str()); setID(in->getAttributeAsInt("Id")); 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"); + TabOrder = in->getAttributeAsInt("TabOrder"); core::position2di p = in->getAttributeAsPosition2d("MaxSize"); setMaxSize(core::dimension2di(p.X,p.Y)); @@ -904,6 +1015,12 @@ protected: //! type of element EGUI_ELEMENT_TYPE Type; + + //! STARSONATA, MICHA: We use names to find elements and assign the ID's automatically + core::stringc Name; + + //! Starsonata, MICHA: textID for stringtables + core::stringw TextID; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIEnvironment.h Irrlicht_starsonata/include/IGUIEnvironment.h --- irrlicht-svn-ss/trunk/include/IGUIEnvironment.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIEnvironment.h 2008-05-31 04:53:40.000000000 +0200 @@ -9,8 +9,10 @@ #include "IGUISkin.h" #include "rect.h" #include "EMessageBoxFlags.h" +#include "EWindowFlags.h" #include "IEventReceiver.h" #include "IXMLReader.h" +#include "EAttributes.h" namespace irr { @@ -55,6 +57,9 @@ class IGUIToolBar; class IGUIButton; class IGUIWindow; class IGUIElementFactory; +class IGUITable; +class IGUIRectangle; // JEFF, StarSonata +class IGUIFontFactory; // MICHA, StarSonata //! GUI Environment. Used as factory and manager of all other GUI elements. class IGUIEnvironment : public virtual IUnknown @@ -130,12 +135,12 @@ public: See IUnknown::drop() for more information. */ virtual IGUISkin* createSkin(EGUI_SKIN_TYPE type) = 0; - //! Returns pointer to the font with the specified file name. + //! Returns pointer to the font with the specified fontname (usually a filename) /** Loads the font if it was not loaded before. Returns 0 if the font could not be loaded. \return returns a pointer to the font. This pointer should not be dropped. See IUnknown::drop() for more information. */ - virtual IGUIFont* getFont(const c8* filename) = 0; + virtual IGUIFont* getFont(const c8* fontname) = 0; //! Returns the default built-in font. virtual IGUIFont* getBuiltInFont() = 0; @@ -172,7 +177,7 @@ public: Returns a pointer to the created window. Returns 0 if an error occured. This pointer should not be dropped. See IUnknown::drop() for more information. */ virtual IGUIWindow* addWindow(const core::rect& rectangle, bool modal = false, - const wchar_t* text=0, IGUIElement* parent=0, s32 id=-1) = 0; + const wchar_t* text=0, s32 flags=EWF_CLOSE|EWF_TITLEBAR, IGUIElement* parent=0, s32 id=-1) = 0; //! Adds a modal screen. This control stops its parent's members from being //! able to recieve input until its last child is removed, it then deletes its self. @@ -196,7 +201,8 @@ public: Returns a pointer to the created message box. Returns 0 if an error occured. This pointer should not be dropped. See IUnknown::drop() for more information. */ virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, - bool modal = true, s32 flags = EMBF_OK, IGUIElement* parent=0, s32 id=-1) = 0; + bool modal = true, s32 boxflags = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0, + s32 windowflags=EWF_TITLEBAR) = 0; //! Adds a scrollbar. /** \return @@ -225,6 +231,9 @@ public: virtual IGUIImage* addImage(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0) = 0; + //! JEFF extension adds a rectangle + virtual IGUIRectangle* addRectangle(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1) = 0; + //! Adds a checkbox element. /** \return Returns a pointer to the created check box. Returns 0 if an error occured. @@ -239,6 +248,13 @@ public: virtual IGUIListBox* addListBox(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, bool drawBackground=false) = 0; + //! Adds a table element. + /** \return + Returns a pointer to the created table. Returns 0 if an error occured. + This pointer should not be dropped. See IUnknown::drop() for more information. */ + virtual IGUITable* addTable(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false) = 0; + //! Adds an mesh viewer. Not 100% implemented yet. /** \return Returns a pointer to the created mesh viewer. Returns 0 if an error occured. @@ -295,7 +311,7 @@ public: Returns a pointer to the created edit box. Returns 0 if an error occured. This pointer should not be dropped. See IUnknown::drop() for more information. */ virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect& rectangle, - bool border=true, IGUIElement* parent=0, s32 id=-1) = 0; + bool border=true, bool transparent=false, IGUIElement* parent=0, s32 id=-1) = 0; //! Adds a spin box. /** An edit box with up and down buttons @@ -386,6 +402,17 @@ public: //! Adds a GUI Element by its name virtual IGUIElement* addGUIElement(const c8* elementName, IGUIElement* parent=0) = 0; + //! Adds a font factory to the gui environment. + /** Use this to extend the gui environment with new fonts which it should be + able to create automaticly, for example when loading data from xml files. */ + virtual void registerGUIFontFactory(IGUIFontFactory* factoryToAdd) = 0; + + //! Returns amount of registered font factories. + virtual s32 getRegisteredGUIFontFactoryCount() = 0; + + //! Returns a font factory by index + virtual IGUIFontFactory* getGUIFontFactory(s32 index) = 0; + //! Saves the current gui into a file. //! \param filename: Name of the file. //! \param start: The GUIElement to start with. Root if 0. @@ -418,6 +445,20 @@ public: //! reads an element virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* parent) =0; + //! remove default attribute settings for all element types + virtual void clearDefaultElementAttributes() = 0; + + //! load a set of default attribute settings from a xml file + virtual bool loadDefaultElementAttributes(const c8* filename) = 0; + + //! save current default attribute settings to a xml file + virtual bool saveDefaultElementAttributes(const c8* filename) = 0; + + //! Use the settings of the given IGUIElement as default attribute settings for this element type + virtual void setDefaultElementAttribute(IGUIElement* defaultElement) = 0; + + //! Set how the default attributes for elements should be used + virtual void setDefaultElementAttributeUsage(io::E_DEFAULT_ATTRIBUTE_USAGE usage) = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIFileOpenDialog.h Irrlicht_starsonata/include/IGUIFileOpenDialog.h --- irrlicht-svn-ss/trunk/include/IGUIFileOpenDialog.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIFileOpenDialog.h 2007-11-22 01:28:08.000000000 +0100 @@ -25,8 +25,11 @@ namespace gui virtual ~IGUIFileOpenDialog() {}; //! Returns the filename of the selected file. Returns NULL, if no file was selected. + //! Starsonata, MICHA: only for backward compatibility virtual const wchar_t* getFilename() = 0; + //! Micha, Starsonata: to allow multiple selection of files + virtual const core::array& getSelectedFilenames() const = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIFontFactory.h Irrlicht_starsonata/include/IGUIFontFactory.h --- irrlicht-svn-ss/trunk/include/IGUIFontFactory.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IGUIFontFactory.h 2007-10-22 18:57:04.000000000 +0200 @@ -0,0 +1,42 @@ +// 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 __I_GUI_FONT_FACTORY_H_INCLUDED__ +#define __I_GUI_FONT_FACTORY_H_INCLUDED__ + +#include "IUnknown.h" +#include "EGUIElementTypes.h" + +namespace irr +{ + + +namespace gui +{ + class IGUIFont; + + //! Interface making it possible to dynamicly create fonts + /** To be able to add custom fonts to Irrlicht and to make it possible for the + scene manager to save and load them, simply implement this interface and register it + in your gui environment via IGUIEnvironment::registerGUIFontFactory. + Note: When implementing your own font factory, don't call IGUIEnvironment::grab() to + increase the reference counter of the environment. This is not necessary because the + it will grab() the factory anyway, and otherwise cyclic references will be created. + */ + class IGUIFontFactory : public virtual IUnknown + { + public: + virtual ~IGUIFontFactory() {}; + + //! adds a font to the GUI Environment based on its name + /** \param fontName: Usually filename of the font to add. But specific factories might use this name otherwise. + \return Returns pointer to the new font or null if not successful. */ + virtual IGUIFont* addGUIFont(const c8* fontName) = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // __I_GUI_FONT_FACTORY_H_INCLUDED__ diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIFont.h Irrlicht_starsonata/include/IGUIFont.h --- irrlicht-svn-ss/trunk/include/IGUIFont.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIFont.h 2007-10-22 18:57:04.000000000 +0200 @@ -9,6 +9,9 @@ #include "SColor.h" #include "rect.h" +// STARSONATA, MICHA - needed now for the name +#include "irrString.h" + namespace irr { namespace gui @@ -87,6 +90,15 @@ public: //! Returns the distance between letters virtual s32 getKerningHeight() = 0; + //! STARSONATA, MICHA: Access the font name + core::stringc & getName() + { + return Name; + } + +protected: + //! STARSONATA, MICHA + core::stringc Name; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIImage.h Irrlicht_starsonata/include/IGUIImage.h --- irrlicht-svn-ss/trunk/include/IGUIImage.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIImage.h 2008-05-24 04:00:26.000000000 +0200 @@ -46,6 +46,18 @@ namespace gui //! Returns true if the image is using the alpha channel, false if not virtual bool isAlphaChannelUsed() const = 0; + //! sets the image source rectangle in the texture + virtual void setSourceRect(core::rect sourceRect) = 0; + + // starsonata, micha + //! Reduce the area used for clipping the image + //! All values are relative in percent to total width (for left and right) and height (for top and bottom) + //! Example: To create a typical progressbar which slightly increases you will decrease the right clipping from 100 to 0. + virtual void shrinkClippingArea(f32 left=0.f, f32 top=0.f, f32 right=0.f, f32 bottom=0.f) = 0; + + // starsonata, micha + //! rotate image + virtual void setRotationDegrees(f32 angle) = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIListBox.h Irrlicht_starsonata/include/IGUIListBox.h --- irrlicht-svn-ss/trunk/include/IGUIListBox.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIListBox.h 2008-06-06 07:04:56.000000000 +0200 @@ -6,6 +6,9 @@ #define __I_GUI_LIST_BOX_BAR_H_INCLUDED__ #include "IGUIElement.h" +// -------------------------------------------------------- +#include "SColor.h" +// -------------------------------------------------------- namespace irr { @@ -13,12 +16,71 @@ namespace gui { class IGUIFont; class IGUISpriteBank; + class IGUIScrollBar; + + enum EGUI_LISTBOX_COLOR + { + EGUI_LBC_TEXT, + EGUI_LBC_TEXT_HIGHLIGHT, + EGUI_LBC_ICON, + EGUI_LBC_ICON_HIGHLIGHT, + + EGUI_LBC_SIZE + }; + + enum EGUI_LISTBOX_SELECTION + { + //! no lines can be selected + EGUI_LBS_NOT_SELECTABLE, + + //! only single lines can be selected (this is default) + EGUI_LBS_SINGLE_SELECTION, + + //! multiple lines can be selected + EGUI_LBS_MULTI_SELECTION + }; + + //! Names for selection modes + const c8* const GUIListBoxSelectionNames[] = + { + "notSelectable", + "singleSelection", + "multiSelection", + 0 + }; + + enum EGUI_LISTBOX_SCROLLING + { + //! don't scroll the listbox automatically + EGUI_LBSC_MANUAL, + //! always scroll so that the selected item is visible + EGUI_LBSC_TO_SELECTED, + //! scroll to the latest item which was added or inserted + EGUI_LBSC_TO_ADDED, + //! like EGUI_LBSC_TO_SELECTED + EGUI_LBSC_TO_ADDED + EGUI_LBSC_TO_ACTIVE, + //! Similar to EGUI_LBSC_TO_ACTIVE, + //! but don't scroll to the newest added item when the thumb is not + //! in the lowest position (avoid hindering users scrolling up while adding messages). + EGUI_LBSC_CHATLIKE + }; + + //! Names for EGUI_LISTBOX_SCROLLING + const c8* const GUIListBoxScrollingNames[] = + { + "manual", + "selected", + "added", + "active", + "chatlike", + 0 + }; + //! Default list box GUI element. class IGUIListBox : public IGUIElement { public: - //! constructor IGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) : IGUIElement(EGUIET_LIST_BOX, environment, parent, id, rectangle) {} @@ -63,14 +125,112 @@ namespace gui //! sets the selected item. Set this to -1 if no item should be selected virtual void setSelected(s32 id) = 0; - //! set whether the listbox should scroll to show a newly selected item - //! or a new item as it is added to the list. - virtual void setAutoScrollEnabled(bool scroll) = 0; + //! StarSonata, Micha: instead of setAutoScrollEnabled + //! Define when and how the listbox should scroll automaticaly + virtual void setScrollStyle( EGUI_LISTBOX_SCROLLING style=EGUI_LBSC_TO_SELECTED) = 0; - //! returns true if automatic scrolling is enabled, false if not. - virtual bool isAutoScrollEnabled() = 0; + //! StarSonata, Micha: instead of isAutoScrollEnabled + //! Get when and how the listbox will scroll automaticaly + virtual EGUI_LISTBOX_SCROLLING getScrollStyle() const = 0; - }; + //! StarSonata, Micha: replacing recalculateScrollPos + //! Scroll the listbox until the item with the given id is visible + virtual void scrollToItem(s32 id) = 0; + + // StarSonata, Micha: scrollbar visibility + //! Show scrollbar all the time. + //! By default it's only visible when so many items are in the listbox that + //! scrolling will be needed. + virtual void setScrollbarAlwaysVisible(bool always_) = 0; + + // MICHA, StarSonata, multicolor support + //! is the scrollbar set to be visible all the time? + virtual bool isScrollbarAlwaysVisible() const = 0; + + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color, bool includeScrollbar=true) = 0; + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(bool includeScrollbar=true) = 0; + + // MICHA, StarSonata, multicolor support + //! set all item colors at given index to color + virtual void setItemOverrideColor(s32 index, const video::SColor &color) = 0; + + //! set all item colors of specified type at given index to color + virtual void setItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType, const video::SColor &color) = 0; + + //! clear all item colors at index + virtual void clearItemOverrideColor(s32 index) = 0; + + //! clear item color at index for given colortype + virtual void clearItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! has the item at index it's color overwritten? + virtual bool hasItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! return the overwrite color at given item index. + virtual video::SColor getItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! return the default color which is used for the given colorType + virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) = 0; + + //! set the item at the given index + //! If icon is -1 no icon will be used + virtual void setItem(s32 index, const wchar_t* text, s32 icon) = 0; + + //! Insert the item at the given index + //! If icon is -1 no icon will be used + //! Return the index on success or -1 on failure. + virtual s32 insertItem(s32 index, const wchar_t* text, s32 icon) = 0; + + //! Swap the items at the given indices + virtual void swapItems(s32 index1, s32 index2) = 0; + + //! Enables or disables word wrap. Default is disabled. + /** \param enable: If set to true, words going over one line are + broken to the next line. */ + virtual void setWordWrap(bool enable) = 0; + + //! Checks if word wrap is enabled + //! \return true if word wrap is enabled, false otherwise + virtual bool isWordWrapEnabled() = 0; + + //! Set the current selection mode for the listbox lines + virtual void setSelectionMode(EGUI_LISTBOX_SELECTION selection) = 0; + + //! Get the current selection mode for the listbox lines + virtual EGUI_LISTBOX_SELECTION getSelectionMode() const = 0; + + //! Get the number of items which are currently selected + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual s32 getMultiSelectedItemCount() const = 0; + + //! Get the id of the next item with set selection flag + //! returns the first item with selection flag when id=-1 + //! return -1 when no item was found + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual s32 getNextMultiSelectedItem(s32 id=-1) = 0; + + //! Set the selection flag for the item with given id + //! Usually that will be done automatically when the users clicks. + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void setItemMultiSelection(s32 id, bool selected) = 0; + + //! Get the selection flag for the item with given id + //! return true when the item is selected, otherwise returns false + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual bool getItemMultiSelection(s32 id) const = 0; + + //! Clear the selection flags for all items + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void clearAllItemMultiSelections() = 0; + + //! Access the scrollbar + virtual IGUIScrollBar* getScrollBar() const = 0; +}; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIScrollBar.h Irrlicht_starsonata/include/IGUIScrollBar.h --- irrlicht-svn-ss/trunk/include/IGUIScrollBar.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIScrollBar.h 2008-06-05 04:47:02.000000000 +0200 @@ -41,6 +41,22 @@ namespace gui //! sets the current position of the scrollbar virtual void setPos(s32 pos) = 0; + + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color) = 0; + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor() = 0; + + // StarSonata, Micha + //! set the page size used for a variable sized thumb + virtual void setPageSize(s32 pageSize) = 0; + + // StarSonata, Micha + //! get the page size used for a variable sized thumb + virtual s32 getPageSize() = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUISkin.h Irrlicht_starsonata/include/IGUISkin.h --- irrlicht-svn-ss/trunk/include/IGUISkin.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUISkin.h 2008-06-04 06:23:28.000000000 +0200 @@ -95,6 +95,12 @@ namespace gui EGDC_ICON, //! Selected icons in a list or tree EGDC_ICON_HIGH_LIGHT, + // Starsonata, Micha: added for button flashing + //! color used for flashing buttons + EGDC_FLASH_PANE, + // Starsonata, Micha: added to get a different background for active editboxes + //! used instead of EGDC_WINDOW when an editbox has the focus + EGDC_FOCUSED_EDITBOX, //! this value is not used, it only specifies the amount of default colors //! available. EGDC_COUNT @@ -124,6 +130,8 @@ namespace gui "WindowSymbol", "Icon", "IconHighlight", + "FlashPane", + "FocusedEditbox", 0, }; @@ -260,6 +268,29 @@ namespace gui //! folder icon for file selection EGDI_DIRECTORY, + // starsonata, micha - needed some more icon control + + //! show ascending sorting of columns in the guitable + EGDI_SORTED_ASCENDING, + //! show descending sorting of columns in the guitable + EGDI_SORTED_DESCENDING, + //! scroll bar up button + EGDI_CURSOR_UP_PRESSED, + //! scroll bar down button + EGDI_CURSOR_DOWN_PRESSED, + //! scroll bar left button + EGDI_CURSOR_LEFT_PRESSED, + //! scroll bar right button + EGDI_CURSOR_RIGHT_PRESSED, + //! down arrow for dropdown menus + EGDI_DROP_DOWN_PRESSED, + //! tabcontrol left + EGDI_TAB_ARROW_LEFT, + EGDI_TAB_ARROW_LEFT_PRESSED, + //! tabcontrol left + EGDI_TAB_ARROW_RIGHT, + EGDI_TAB_ARROW_RIGHT_PRESSED, + //! value not used, it only specifies the number of icons EGDI_COUNT }; @@ -289,6 +320,17 @@ namespace gui "collapse", "file", "directory", + "sortedAscending", + "sortedDescending", + "cursorUpPressed", + "cursorDownPressed", + "cursorLeftPressed", + "cursorRightPressed", + "dropDownPressed", + "tabArrowLeft", + "tabArrowLeftPressed", + "tabArrowRight", + "tabArrowRightPressed", 0 }; @@ -320,6 +362,32 @@ namespace gui 0 }; + enum EGUI_HORIZONTAL_ALIGNMENT + { + //! Align a gui element to the left + EGHA_LEFT, + + //! Align a gui element to the right + EGHA_RIGHT, + + //! this value is not used, it only specifies the amount of default horizontal alignements + //! available. + EGHA_COUNT + }; + + enum EGUI_VERTICAL_ALIGNMENT + { + //! Align a gui element to the top + EGVA_TOP, + + //! Align a gui element to the bottom + EGVA_BOTTOM, + + //! this value is not used, it only specifies the amount of default vertical alignements + //! available. + EGVA_COUNT + }; + //! A skin modifies the look of the GUI elements. class IGUISkin : public virtual io::IAttributeExchangingObject { @@ -382,9 +450,14 @@ namespace gui implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ + // Starsonata, Micha: added flashing + //! /param flashFrequency: if not zero then use flashing with the frequency set here + //! /param u32 flashTime: when flashFrequency is not zero then this is value controls the flashing. + // The value should be between 0 and flashFrequency, but will be clipped modulated otherwise also. virtual void draw3DButtonPaneStandard(IGUIElement* element, const core::rect& rect, - const core::rect* clip=0) = 0; + const core::rect* clip=0, + u32 flashFrequency=0, u32 flashTime=0 ) = 0; //! draws a pressed 3d button pane /** Used for drawing for example buttons in pressed state. @@ -395,9 +468,14 @@ namespace gui implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ + // Starsonata, Micha: added flashing + //! /param flashFrequency: if not zero then use flashing with the frequency set here + //! /param u32 flashTime: when flashFrequency is not zero then this is value controls the flashing. + // The value should be between 0 and flashFrequency, but will be clipped modulated otherwise also. virtual void draw3DButtonPanePressed(IGUIElement* element, const core::rect& rect, - const core::rect* clip=0) = 0; + const core::rect* clip=0, + u32 flashFrequency=0, u32 flashTime=0 ) = 0; //! draws a sunken 3d pane /** Used for drawing the background of edit, combo or check boxes. @@ -464,7 +542,7 @@ namespace gui \param rect: Defining area where to draw. \param clip: Clip area. */ virtual void draw3DTabButton(IGUIElement* element, bool active, - const core::rect& rect, const core::rect* clip=0) = 0; + const core::rect& rect, const core::rect* clip=0, EGUI_VERTICAL_ALIGNMENT alignment=EGVA_TOP) = 0; //! draws a tab control body /** \param element: Pointer to the element which wishes to draw this. This parameter @@ -473,9 +551,10 @@ namespace gui \param border: Specifies if the border should be drawn. \param background: Specifies if the background should be drawn. \param rect: Defining area where to draw. - \param clip: Clip area. */ + \param clip: Clip area. + \param tabHeight: Defines the height of the tabs.*/ virtual void draw3DTabBody(IGUIElement* element, bool border, bool background, - const core::rect& rect, const core::rect* clip=0) = 0; + const core::rect& rect, const core::rect* clip=0, s32 tabHeight=-1, EGUI_VERTICAL_ALIGNMENT alignment=EGVA_TOP ) = 0; //! draws an icon, usually from the skin's sprite bank /** \param element: Pointer to the element which wishes to draw this icon. diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUISpriteBank.h Irrlicht_starsonata/include/IGUISpriteBank.h --- irrlicht-svn-ss/trunk/include/IGUISpriteBank.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUISpriteBank.h 2008-04-11 11:40:44.000000000 +0200 @@ -40,6 +40,14 @@ public: //! Destructor virtual ~IGUISpriteBank() {}; + //! clears sprites, rectangles and textures + virtual void clear() = 0; + + //! Use the whole texture as one non-animated sprite + //! The texture and the corresponding rectangle and sprite will all be added to the end of each array. + //! returns the index of the sprite or -1 on failure + virtual s32 addTextureAsSprite(video::ITexture* texture) = 0; + //! Returns the list of rectangles held by the sprite bank virtual core::array< core::rect >& getPositions() = 0; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIStaticText.h Irrlicht_starsonata/include/IGUIStaticText.h --- irrlicht-svn-ss/trunk/include/IGUIStaticText.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIStaticText.h 2008-06-03 07:57:46.000000000 +0200 @@ -59,8 +59,13 @@ namespace gui //! \return true if the override color is enabled, false otherwise virtual bool isOverrideColorEnabled(void) = 0; - //! Sets another color for the background. - virtual void setBackgroundColor(video::SColor color) = 0; + // StarSonata, Micha - this replaces the old setBackgroundColor + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color) = 0; + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor() = 0; //! Sets whether to draw the background virtual void setDrawBackground(bool draw) = 0; @@ -95,6 +100,23 @@ namespace gui \return The width of the text, or the widest broken line. */ virtual s32 getTextWidth(void) = 0; + // Starsonata, Micha + //! scroll a static with wordwrap + //! numberOfLines_ is added to the currently scrolled lines + //! resetting to the orinal state is done with scrollLines(-getScrolledLines()) + virtual void scrollLines(s32 numberOfLines_) = 0; + + // Starsonata, Micha + //! get the amount of lines which are scrolled + virtual s32 getScrolledLines() const = 0; + + // Starsonata, Micha + //! get the number of lines in the static. Will be at least 1. + virtual u32 getLineCount() const = 0; + + // Starsonata, Micha + //! Return the font which is currently used for this element + virtual IGUIFont* getCurrentFont() = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUITabControl.h Irrlicht_starsonata/include/IGUITabControl.h --- irrlicht-svn-ss/trunk/include/IGUITabControl.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUITabControl.h 2008-06-13 21:16:34.000000000 +0200 @@ -7,6 +7,7 @@ #include "IGUIElement.h" #include "SColor.h" +#include "IGUISkin.h" namespace irr { @@ -34,6 +35,12 @@ namespace gui //! sets the color of the background, if it should be drawn. virtual void setBackgroundColor(video::SColor c) = 0; + //! sets the color of the text + virtual void setTextColor(video::SColor c) = 0; + + //! gets the color of the text + virtual video::SColor getTextColor() = 0; + //! returns true if the tab is drawing its background, false if not virtual bool isDrawingBackground() const = 0; @@ -66,6 +73,14 @@ namespace gui is corresponding to this tab. */ virtual IGUITab* getTab(s32 idx) = 0; + // Micha, Starsonata + //! remove tab for given index + virtual void removeTab(s32 idx) = 0; + + // Micha, Starsonata + //! remove all tabs + virtual void clearTabs() = 0; + //! Brings a tab to front. /** \param idx: number of the tab. \return Returns true if successful. */ @@ -78,6 +93,27 @@ namespace gui //! Returns which tab is currently active virtual s32 getActiveTab() = 0; + + //! Set the height of the tabs + virtual void setTabHeight( s32 height ) = 0; + + //! Get the height of the tabs + /** return Returns the height of the tabs */ + virtual s32 getTabHeight() = 0; + + //! Set the alignment of the tabs + virtual void setTabVerticalAlignment( gui::EGUI_VERTICAL_ALIGNMENT alignment ) = 0; + + //! Get the alignment of the tabs + /** return Returns the alignment of the tabs */ + virtual gui::EGUI_VERTICAL_ALIGNMENT getTabVerticalAlignment() = 0; + + //! Set the extra width added to tabs on each side of the text + virtual void setTabExtraWidth( s32 extraWidth ) = 0; + + //! Get the extra width added to tabs on each side of the text + /** return Returns the extra width of the tabs */ + virtual s32 getTabExtraWidth() = 0; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUITable.h Irrlicht_starsonata/include/IGUITable.h --- irrlicht-svn-ss/trunk/include/IGUITable.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IGUITable.h 2008-06-17 23:06:34.000000000 +0200 @@ -0,0 +1,285 @@ +// Copyright (C) 2003-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_TABLE_H_INCLUDED__ +#define __I_GUI_TABLE_H_INCLUDED__ + +#include "IGUIElement.h" +#include "irrTypes.h" +#include "SColor.h" +#include "IGUISkin.h" + +namespace irr +{ +namespace gui +{ + + //! modes for ordering used when a column header is clicked + enum EGUI_COLUMN_ORDERING + { + //! Do not use ordering + EGCO_NONE, + + //! Send a EGET_TABLE_HEADER_CHANGED message when a column header is clicked. + EGCO_CUSTOM, + + //! Sort it ascending by it's ascii value like: a,b,c,... + EGCO_ASCENDING, + + //! Sort it descending by it's ascii value like: z,x,y,... + EGCO_DESCENDING, + + //! Sort it ascending on first click, descending on next, etc + EGCO_FLIP_ASCENDING_DESCENDING, + + //! Not used as mode, only to get maximum value for this enum + EGCO_COUNT + }; + + //! Names for EGUI_COLUMN_ORDERING types + const c8* const GUIColumnOrderingNames[] = + { + "none", + "custom", + "ascend", + "descend", + "ascend_descend", + 0, + }; + + enum EGUI_ORDERING_MODE + { + //! No element ordering + EGOM_NONE, + + //! Elements are ordered from the smallest to the largest. + EGOM_ASCENDING, + + //! Elements are ordered from the largest to the smallest. + EGOM_DESCENDING, + + //! this value is not used, it only specifies the amount of default ordering types + //! available. + EGOM_COUNT + }; + + const c8* const GUIOrderingModeNames[] = + { + "none", + "ascending", + "descending", + 0 + }; + + enum EGUI_TABLE_DRAW_FLAGS + { + EGTDF_ROWS = 1, + EGTDF_COLUMNS = 2, + EGTDF_ACTIVE_ROW = 4, + EGTDF_HIDE_HEADER = 8, + + EGTDF_COUNT, + }; + + enum EGUI_TABLE_COLUMN_RESIZE + { + //! Make sure all texts, including headers and padding, do fit. + //! If there's room to the right, do fill it with the most-right column. + ETCR_FIT_TEXTS, + }; + + class IGUIFont; + + //! Default list box GUI element. + class IGUITable : public IGUIElement + { + public: + //! constructor + IGUITable(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_TABLE, environment, parent, id, rectangle) {} + + //! Adds a column + //! If columnIndex is outside the current range, do push new colum at the end + virtual void addColumn(const wchar_t* caption, s32 columnIndex=-1) = 0; + + //! Set the name for the given column. + //! Column must exist, otherwise nothing will happen. + virtual void setColumnName(u32 columnIndex, const wchar_t* name) = 0; + + //! remove a column from the table + virtual void removeColumn(u32 columnIndex) = 0; + + //! Returns the number of columns in the table control + virtual s32 getColumnCount() const = 0; + + //! Makes a column active. This will trigger an ordering process. + /** \param idx: The id of the column to make active. + //! \param doOrder: Do also the ordering which depending on mode for active column + \return Returns true if successful. */ + virtual bool setActiveColumn(s32 idx, bool doOrder=false) = 0; + + //! Returns which header is currently active + virtual s32 getActiveColumn() const = 0; + + //! Returns the ordering used by the currently active column + virtual EGUI_ORDERING_MODE getActiveColumnOrdering() const = 0; + + //! Set the width of a column + virtual void setColumnWidth(u32 columnIndex, u32 width) = 0; + + //! Get the size which the widest text within this column would need + //! \param includePadding_: add the usual padding on both sides + //! \param includeHeader_: Also regard the width of the header text + virtual u32 getColumnTextWidth(u32 columnIndex, bool includePadding=true, bool includeHeader=true) const = 0; + + //! columns can be resized by drag 'n drop + virtual void setResizableColumns(bool resizable) = 0; + + //! can columns be resized by drag 'n drop? + virtual bool hasResizableColumns() const = 0; + + // micha, starsonata + //! some comfortable resizing of column widths + virtual void resizeAllColumns(EGUI_TABLE_COLUMN_RESIZE style=ETCR_FIT_TEXTS) = 0; + + //! This tells the table control which ordering mode should be used when + //! a column header is clicked. + /** \param columnIndex: The index of the column header. + \param state: If true, a EGET_TABLE_HEADER_CHANGED message will be sent and you can order the table data as you whish.*/ + //! \param mode: One of the modes defined in EGUI_COLUMN_ORDERING + virtual void setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode) = 0; + + //! Returns which row is currently selected + virtual s32 getSelected() const = 0; + + //! Select the row or comletely remove selection by using a rowIndex of -1 + //! if you set triggerEvent to true an EGET_TABLE_CHANGED or EGET_TABLE_SELECTED_AGAIN event will get triggered + virtual void setSelected(s32 rowIndex, bool triggerEvent=false)= 0; + + //! Select the row by the y coordinate of a mouse position + //! If the mousepos is above the top-row the selection won't be changed + //! If the mousepos is below the guielement rectangle the selection won't be changed + //! If the mousepos is below the bottom row, but within the guielement rectangle then the selection will be set to -1 (no selection) + virtual void selectRowByPosY(s32 ypos, bool triggerEvent=false) = 0; + + //! scroll to the row if it's not visible currently + virtual void ensureRowVisibility(s32 rowIndex) = 0; + + //! Returns amount of rows in the tabcontrol + virtual u32 getRowCount() const = 0; + + //! adds a row to the table + /* \param rowIndex: zero based index of rows. The row will be inserted at this + position or pushed at the end for indices beyond the current tablesize */ + virtual void addRow(u32 rowIndex) = 0; + + //! sets all cell texts in a row (or at least as many as contained in cellTexts) + /* \param rowIndex: zero based index of rows. It must exit or nothing will happen*/ + //! \param cellTexts: contains the text for all the cells in a row. Each string will be filled in one column. + virtual void setRowTexts(u32 rowIndex, const irr::core::array &cellTexts ) = 0; + + //! set some custom data for the given row + //! \param data: custom data pointer + virtual void setRowData(u32 rowIndex, void * data) = 0; + + //! get the custom row data + virtual void* getRowData(u32 rowIndex) const = 0; + + //! Remove a row from the table + //! returns true on success and false if the index did not exist + virtual bool removeRow(u32 rowIndex) = 0; + + //! clears the table rows, but keeps the columns intact + virtual void clearRows() = 0; + + //! Swap two row positions. This is useful for a custom ordering algo. + virtual void swapRows(u32 rowIndexA, u32 rowIndexB) = 0; + + //! find the index of the row which contains the same custom data value + //! returns -1 when it did not find it + virtual s32 findRowIndexByData(void *data) const = 0; + + //! This tells the table to start ordering all the rows. You need to explicitly + //! tell the table to re order the rows when a new row is added or the cells data is + //! changed. This makes the system more flexible and doesn't make you pay the cost of + //! ordering when adding a lot of rows. + //! \param columnIndex: When set to -1 the active column is used. + virtual void orderRows(s32 columnIndex=-1, EGUI_ORDERING_MODE mode=EGOM_NONE) = 0; + + //! This tells the table to start ordering all the rows with a custom compare function. + //! \param compareFn: The comparison should return negative numbers if idx1 should be above idx2. See example below. + //! \param data: custom data. Often used to pass the this pointer of class objects + //! Example for compareFn which sort from small to larger numbers from top to bottom (ignoring data): + //! static int MyCompare(u32 idx1, u32 idx2, void * data) + //! { return idx1-idx2; } + virtual void orderRows( s32 (*compareFn)(u32 idx1, u32 idx2, void * data), void * data=NULL ) = 0; + + //! This tells the table to start ordering all the rows with a custom compare function which works with the rowdata + //! \param compareFn: The comparison should return negative numbers if rowdata1 should be above rowdata2. + //! \param customdata: Often used to pass the this pointer of class objects + //! Example for compareFn which sort by the pointer value, so that rows with smaller rowdata pointers will be on top. + //! static int MyCompare(void * rowdata1, void * rowdata2, void * customdata) + //! { return rowdata1-rowdata2; } + virtual void orderRows( s32 (*compareFn)(void * rowdata1, void * rowdata2, void * customdata), void * customdata=NULL ) = 0; + + //! override the background color of given row + virtual void setRowOverrideBackground(u32 rowIndex, const video::SColor &color) = 0; + + //! clear override of the background color of given row + virtual void clearRowOverrideBackground(u32 rowIndex) = 0; + + //! Set the text of a cell + virtual void setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text) = 0; + + //! Set the text of a cell, and set a color of this cell. + virtual void setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text, video::SColor color) = 0; + + //! Set the data of a cell + virtual void setCellData(u32 rowIndex, u32 columnIndex, void *data) = 0; + + //! Set the color of a cell text + virtual void setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) = 0; + + //! Set the text of all cells in the given row + virtual void setCellColorsInRow(u32 rowIndex, video::SColor color) = 0; + + //! Get the text of a cell + virtual const wchar_t* getCellText(u32 rowIndex, u32 columnIndex ) const = 0; + + //! Get the data of a cell + virtual void* getCellData(u32 rowIndex, u32 columnIndex ) const = 0; + + //! \param icon Sprite index of the Icon within the current sprite bank + virtual void setCellIcon(u32 rowIndex, u32 columnIndex, s32 icon) = 0; + + //! get the sprite index of the icon in that cell or -1 for no icon + virtual s32 getCellIcon(u32 rowIndex, u32 columnIndex) const = 0; + + //! set the spritebank used for icons + virtual void setSpriteBank(const c8 *bankName) = 0; + + //! clears the table, deletes all items in the table + virtual void clear() = 0; + + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color) = 0; + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor() = 0; + + //! Set flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual void setDrawFlags(s32 flags) = 0; + + //! Get the flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual s32 getDrawFlags() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIWindow.h Irrlicht_starsonata/include/IGUIWindow.h --- irrlicht-svn-ss/trunk/include/IGUIWindow.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIWindow.h 2008-05-31 04:53:20.000000000 +0200 @@ -7,6 +7,7 @@ #include "IGUIElement.h" #include "EMessageBoxFlags.h" +#include "EWindowFlags.h" namespace irr { @@ -34,8 +35,36 @@ namespace gui //! Returns pointer to the maximize button virtual IGUIButton* getMaximizeButton() = 0; - }; + //! On EGET_WINDOW_SIZING events you can access and change the sizing rect + //! The rect is in relative posisitions + virtual core::rect * getSizingRect() = 0; + + // starsonata, micha + //! return if given flag is set + virtual bool hasFlag( EWINDOW_FLAG flag ) = 0; + + // starsonata, micha, bunch of flags which turned out to be useful + virtual void setTopResizable(bool resizable) = 0; + virtual bool isTopResizable() const = 0; + virtual void setRightResizable(bool resizable) = 0; + virtual bool isRightResizable() const = 0; + virtual void setBottomResizable(bool resizable) = 0; + virtual bool isBottomResizable() const = 0; + virtual void setLeftResizable(bool resizable) = 0; + virtual bool isLeftResizable() const = 0; + virtual void setMovable(bool movable) = 0; + virtual bool isMovable() const = 0; + virtual void setDrawBackground(bool draw) = 0; + virtual bool getDrawBackground() const = 0; + + // starsonata, micha + //! define the way the borders should look like + //! It's up to the skin to interpret the style + //! For example 0 = no border, 1 = normal border, 2 = soft border + virtual void setBorderStyle(u32 style=1) = 0; + virtual u32 getBorderStyle() const = 0; + }; } // end namespace gui } // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IImage.h Irrlicht_starsonata/include/IImage.h --- irrlicht-svn-ss/trunk/include/IImage.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IImage.h 2008-05-08 00:58:34.000000000 +0200 @@ -104,6 +104,12 @@ public: //! copies the image into the target, scaling the image to fit virtual void copyToScaling(IImage* target) = 0; + //! copies this surface into another + virtual void copyTo(IImage* target, const core::position2d& pos=core::position2d(0,0)) = 0; + + // starsonata, micha, needed this for padding d3d textures + //! copies this surface into another + virtual void copyTo(void* target, s32 width, s32 height, ECOLOR_FORMAT format, u32 pitch=0, const core::position2d& pos=core::position2d(0,0)) = 0; }; } // end namespace video diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleAffector.h Irrlicht_starsonata/include/IParticleAffector.h --- irrlicht-svn-ss/trunk/include/IParticleAffector.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IParticleAffector.h 2008-06-04 00:40:52.000000000 +0200 @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2002-2008 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -17,8 +17,10 @@ namespace scene enum E_PARTICLE_AFFECTOR_TYPE { EPAT_NONE = 0, + EPAT_ATTRACT, EPAT_FADE_OUT, EPAT_GRAVITY, + EPAT_ROTATE, EPAT_COUNT }; @@ -26,8 +28,10 @@ enum E_PARTICLE_AFFECTOR_TYPE const c8* const ParticleAffectorTypeNames[] = { "None", + "Attract", "FadeOut", "Gravity", + "Rotate", 0 }; @@ -46,15 +50,15 @@ public: virtual void affect(u32 now, SParticle* particlearray, u32 count) = 0; //! Sets whether or not the affector is currently enabled. - virtual void setEnabled(bool enabled) {Enabled = enabled;} + virtual void setEnabled(bool enabled) { Enabled = enabled; } //! Gets whether or not the affector is currently enabled. - virtual bool getEnabled() const { return Enabled;} + virtual bool getEnabled() const { return Enabled; } //! 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. - virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) {} + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {} //! Reads attributes of the object. //! Implement this to set the attributes of your scene node animator for diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleAnimatedMeshSceneNodeEmitter.h Irrlicht_starsonata/include/IParticleAnimatedMeshSceneNodeEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleAnimatedMeshSceneNodeEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleAnimatedMeshSceneNodeEmitter.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,56 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" +#include "IAnimatedMeshSceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits particles from mesh vertices. +class IParticleAnimatedMeshSceneNodeEmitter : public IParticleEmitter +{ +public: + + //! Set Mesh to emit particles from + virtual void setAnimatedMeshSceneNode( IAnimatedMeshSceneNode* node ) = 0; + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection = true ) = 0; + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) = 0; + + //! Sets whether to emit min<->max particles for every vertex per + //! second, or to pick min<->max vertices every second + virtual void setEveryMeshVertex( bool everyMeshVertex = true ) = 0; + + //! Get Mesh we're emitting particles from + virtual const IAnimatedMeshSceneNode* getAnimatedMeshSceneNode() const = 0; + + //! Get whether to use vertex normal for direction, or direction specified + virtual bool isUsingNormalDirection() const = 0; + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const = 0; + + //! Gets whether to emit min<->max particles for every vertex per + //! second, or to pick min<->max vertices every second + virtual bool getEveryMeshVertex() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_ANIMATED_MESH; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleAttractionAffector.h Irrlicht_starsonata/include/IParticleAttractionAffector.h --- irrlicht-svn-ss/trunk/include/IParticleAttractionAffector.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleAttractionAffector.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which attracts or detracts particles. +class IParticleAttractionAffector : public IParticleAffector +{ +public: + + //! Set the point that particles will attract to + virtual void setPoint( const core::vector3df& point ) = 0; + + //! Set whether or not the particles are attracting or detracting + virtual void setAttract( bool attract ) = 0; + + //! Set whether or not this will affect particles in the X direction + virtual void setAffectX( bool affect ) = 0; + + //! Set whether or not this will affect particles in the Y direction + virtual void setAffectY( bool affect ) = 0; + + //! Set whether or not this will affect particles in the Z direction + virtual void setAffectZ( bool affect ) = 0; + + //! Get the point that particles are attracted to + virtual const core::vector3df& getPoint() const = 0; + + //! Get whether or not the particles are attracting or detracting + virtual bool getAttract() const = 0; + + //! Get whether or not the particles X position are affected + virtual bool getAffectX() const = 0; + + //! Get whether or not the particles Y position are affected + virtual bool getAffectY() const = 0; + + //! Get whether or not the particles Z position are affected + virtual bool getAffectZ() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const { return EPAT_ATTRACT; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleBoxEmitter.h Irrlicht_starsonata/include/IParticleBoxEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleBoxEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleBoxEmitter.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,36 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_BOX_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_BOX_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" +#include "aabbox3d.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits particles from a box shaped space +class IParticleBoxEmitter : public IParticleEmitter +{ +public: + + //! Set the box shape + virtual void setBox( const core::aabbox3df& box ) = 0; + + //! Get the box shape set + virtual const core::aabbox3df& getBox() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_BOX; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleCylinderEmitter.h Irrlicht_starsonata/include/IParticleCylinderEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleCylinderEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleCylinderEmitter.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_CYLINDER_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_CYLINDER_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits from a cylindrically shaped space. +class IParticleCylinderEmitter : public IParticleEmitter +{ +public: + + //! Set the center of the radius for the cylinder, at one end of the cylinder + virtual void setCenter( const core::vector3df& center ) = 0; + + //! Set the normal of the cylinder + virtual void setNormal( const core::vector3df& normal ) = 0; + + //! Set the radius of the cylinder + virtual void setRadius( f32 radius ) = 0; + + //! Set the length of the cylinder + virtual void setLength( f32 length ) = 0; + + //! Set whether or not to draw points inside the cylinder + virtual void setOutlineOnly( bool outlineOnly = true ) = 0; + + //! Get the center of the cylinder + virtual const core::vector3df& getCenter() const = 0; + + //! Get the normal of the cylinder + virtual const core::vector3df& getNormal() const = 0; + + //! Get the radius of the cylinder + virtual f32 getRadius() const = 0; + + //! Get the center of the cylinder + virtual f32 getLength() const = 0; + + //! Get whether or not to draw points inside the cylinder + virtual bool getOutlineOnly() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_CYLINDER; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleEmitter.h Irrlicht_starsonata/include/IParticleEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleEmitter.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IParticleEmitter.h 2008-06-04 00:40:52.000000000 +0200 @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2002-2008 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -17,7 +17,12 @@ namespace scene enum E_PARTICLE_EMITTER_TYPE { EPET_POINT = 0, + EPET_ANIMATED_MESH, EPET_BOX, + EPET_CYLINDER, + EPET_MESH, + EPET_RING, + EPET_SPHERE, EPET_COUNT }; @@ -25,7 +30,12 @@ enum E_PARTICLE_EMITTER_TYPE const c8* const ParticleEmitterTypeNames[] = { "Point", + "AnimatedMesh", "Box", + "Cylinder", + "Mesh", + "Ring", + "Sphere", 0 }; @@ -36,9 +46,6 @@ class IParticleEmitter : public virtual { public: - //! destructor - virtual ~IParticleEmitter() {}; - //! Prepares an array with new particles to emitt into the system //! and returns how much new particles there are. //! \param now: Current time. @@ -48,10 +55,40 @@ public: //! \return Returns amount of new particles in the array. Can be 0. virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) = 0; + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) = 0; + + //! Set minimum number of particles the emitter emits per second + virtual void setMinParticlesPerSecond( u32 minPPS ) = 0; + + //! Set maximum number of particles the emitter emits per second + virtual void setMaxParticlesPerSecond( u32 maxPPS ) = 0; + + //! Set minimum starting color for particles + virtual void setMinStartColor( const video::SColor& color ) = 0; + + //! Set maximum starting color for particles + virtual void setMaxStartColor( const video::SColor& color ) = 0; + + //! Get direction the emitter emits particles + virtual const core::vector3df& getDirection() const = 0; + + //! Get the minimum number of particles the emitter emits per second + virtual u32 getMinParticlesPerSecond() const = 0; + + //! Get the maximum number of particles the emitter emits per second + virtual u32 getMaxParticlesPerSecond() const = 0; + + //! Get the minimum starting color for particles + virtual const video::SColor& getMinStartColor() const = 0; + + //! Get the maximum starting color for particles + virtual const video::SColor& getMaxStartColor() const = 0; + //! 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. - virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) {} + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {} //! Reads attributes of the object. //! Implement this to set the attributes of your scene node animator for @@ -63,9 +100,11 @@ public: virtual s32 deserializeAttributes(s32 startIndex, io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { return 0; } //! Get emitter type - virtual E_PARTICLE_EMITTER_TYPE getType() const = 0; + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_POINT; } }; +typedef IParticleEmitter IParticlePointEmitter; + } // end namespace scene } // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleFadeOutAffector.h Irrlicht_starsonata/include/IParticleFadeOutAffector.h --- irrlicht-svn-ss/trunk/include/IParticleFadeOutAffector.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleFadeOutAffector.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,43 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which fades out the particles. +class IParticleFadeOutAffector : public IParticleAffector +{ +public: + + //! Sets the targetColor, i.e. the color the particles will interpolate + //! to over time. + virtual void setTargetColor( const video::SColor& targetColor ) = 0; + + //! Sets the amount of time it takes for each particle to fade out. + virtual void setFadeOutTime( f32 fadeOutTime ) = 0; + + //! Gets the targetColor, i.e. the color the particles will interpolate + //! to over time. + virtual const video::SColor& getTargetColor() const = 0; + + //! Gets the amount of time it takes for each particle to fade out. + virtual f32 getFadeOutTime() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const { return EPAT_FADE_OUT; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleGravityAffector.h Irrlicht_starsonata/include/IParticleGravityAffector.h --- irrlicht-svn-ss/trunk/include/IParticleGravityAffector.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleGravityAffector.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,43 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which applies gravity to particles. +class IParticleGravityAffector : public IParticleAffector +{ +public: + + //! Set the time in milliseconds when the gravity force is totally + //! lost and the particle does not move any more. + virtual void setTimeForceLost( f32 timeForceLost ) = 0; + + //! Set the direction and force of gravity in all 3 dimensions. + virtual void setGravity( const core::vector3df& gravity ) = 0; + + //! Get the time in milliseconds when the gravity force is totally + //! lost and the particle does not move any more. + virtual f32 getTimeForceLost() const = 0; + + //! Get the direction and force of gravity. + virtual const core::vector3df& getGravity() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const { return EPAT_GRAVITY; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleMeshEmitter.h Irrlicht_starsonata/include/IParticleMeshEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleMeshEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleMeshEmitter.h 2008-06-04 00:40:48.000000000 +0200 @@ -0,0 +1,56 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_MESH_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_MESH_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits from vertices of a mesh +class IParticleMeshEmitter : public IParticleEmitter +{ +public: + + //! Set Mesh to emit particles from + virtual void setMesh( IMesh* mesh ) = 0; + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection = true ) = 0; + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) = 0; + + //! Sets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual void setEveryMeshVertex( bool everyMeshVertex = true ) = 0; + + //! Get Mesh we're emitting particles from + virtual const IMesh* getMesh() const = 0; + + //! Get whether to use vertex normal for direction, or direction specified + virtual bool isUsingNormalDirection() const = 0; + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const = 0; + + //! Gets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual bool getEveryMeshVertex() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_MESH; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleRingEmitter.h Irrlicht_starsonata/include/IParticleRingEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleRingEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleRingEmitter.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,47 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_RING_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_RING_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits particles along a ring shaped area. +class IParticleRingEmitter : public IParticleEmitter +{ +public: + + //! Set the center of the ring + virtual void setCenter( const core::vector3df& center ) = 0; + + //! Set the radius of the ring + virtual void setRadius( f32 radius ) = 0; + + //! Set the thickness of the ring + virtual void setRingThickness( f32 ringThickness ) = 0; + + //! Get the center of the ring + virtual const core::vector3df& getCenter() const = 0; + + //! Get the radius of the ring + virtual f32 getRadius() const = 0; + + //! Get the thickness of the ring + virtual f32 getRingThickness() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_RING; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleRotationAffector.h Irrlicht_starsonata/include/IParticleRotationAffector.h --- irrlicht-svn-ss/trunk/include/IParticleRotationAffector.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleRotationAffector.h 2008-06-04 00:40:52.000000000 +0200 @@ -0,0 +1,41 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which rotates the particle system. +class IParticleRotationAffector : public IParticleAffector +{ +public: + + //! Set the point that particles will rotate around + virtual void setPivotPoint( const core::vector3df& point ) = 0; + + //! Set the speed in degrees per second in all 3 dimensions + virtual void setSpeed( const core::vector3df& speed ) = 0; + + //! Get the point that particles are attracted to + virtual const core::vector3df& getPivotPoint() const = 0; + + //! Get the speed in degrees per second in all 3 dimensions + virtual const core::vector3df& getSpeed() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const { return EPAT_ROTATE; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleSphereEmitter.h Irrlicht_starsonata/include/IParticleSphereEmitter.h --- irrlicht-svn-ss/trunk/include/IParticleSphereEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/IParticleSphereEmitter.h 2008-06-04 00:40:50.000000000 +0200 @@ -0,0 +1,41 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_SPHERE_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_SPHERE_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits from a spherical space. +class IParticleSphereEmitter : public IParticleEmitter +{ +public: + + //! Set the center of the sphere for particle emissions + virtual void setCenter( const core::vector3df& center ) = 0; + + //! Set the radius of the sphere for particle emissions + virtual void setRadius( f32 radius ) = 0; + + //! Get the center of the sphere for particle emissions + virtual const core::vector3df& getCenter() const = 0; + + //! Get the radius of the sphere for particle emissions + virtual f32 getRadius() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_SPHERE; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IParticleSystemSceneNode.h Irrlicht_starsonata/include/IParticleSystemSceneNode.h --- irrlicht-svn-ss/trunk/include/IParticleSystemSceneNode.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IParticleSystemSceneNode.h 2008-06-04 00:40:50.000000000 +0200 @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2002-2008 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -6,8 +6,16 @@ #define __I_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__ #include "ISceneNode.h" -#include "IParticleEmitter.h" -#include "IParticleAffector.h" +#include "IParticleAnimatedMeshSceneNodeEmitter.h" +#include "IParticleBoxEmitter.h" +#include "IParticleCylinderEmitter.h" +#include "IParticleMeshEmitter.h" +#include "IParticleRingEmitter.h" +#include "IParticleSphereEmitter.h" +#include "IParticleAttractionAffector.h" +#include "IParticleFadeOutAffector.h" +#include "IParticleGravityAffector.h" +#include "IParticleRotationAffector.h" #include "dimension2d.h" namespace irr @@ -39,7 +47,7 @@ class IParticleSystemSceneNode : public { public: - //! constructor + //! Constructor IParticleSystemSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, const core::vector3df& position = core::vector3df(0,0,0), const core::vector3df& rotation = core::vector3df(0,0,0), @@ -50,130 +58,367 @@ public: virtual void setParticleSize( const core::dimension2d &size = core::dimension2d(5.0f, 5.0f)) = 0; - //! Sets if the particles should be global. If it is, the particles are affected by - //! the movement of the particle system scene node too, otherwise they completely - //! ignore it. Default is true. + //! Sets if the particles should be global. + /** If it is, the particles are affected by the movement of the + particle system scene node too, otherwise they completely ignore it. + Default is true. */ virtual void setParticlesAreGlobal(bool global) = 0; //! Sets the particle emitter, which creates the particles. - //! A particle emitter can be created using one of the - //! methods. For example to create and use a simple PointEmitter, - //! call IParticleEmitter* p = createPointEmitter(); setEmitter(p); p->drop(); - //! \param emitter: Sets the particle emitter. You can set this to 0 - //! for removing the current emitter and stopping the particle system - //! emitting new particles. + /** A particle emitter can be created using one of the methods. For + example to create and use a simple PointEmitter, call + IParticleEmitter* p = createPointEmitter(); setEmitter(p); p->drop(); + \param emitter: Sets the particle emitter. You can set this to 0 for + removing the current emitter and stopping the particle system emitting + new particles. */ virtual void setEmitter(IParticleEmitter* emitter) = 0; - //! Adds new particle effector to the particle system. A particle - //! affector modifies the particles. For example, the FadeOut - //! affector lets all particles fade out after some time. It is created - //! and used in this way: IParticleAffector* p = createFadeOutParticleAffector(); - //! addAffector(p); p->drop(); - //! Please note that a affector is not necessary for the particle - //! system to work. - //! \param affector: New affector. + //! Adds new particle effector to the particle system. + /** A particle affector modifies the particles. For example, the FadeOut + affector lets all particles fade out after some time. It is created and + used in this way: + \code + IParticleAffector* p = createFadeOutParticleAffector(); + addAffector(p); + p->drop(); + \endcode + Please note that a affector is not necessary for the particle system to + work. + \param affector: New affector. */ virtual void addAffector(IParticleAffector* affector) = 0; //! Removes all particle affectors in the particle system. virtual void removeAllAffectors() = 0; + //! Creates a particle emitter for an animated mesh scene node + /** \param node: Pointer to the animated mesh scene node to emit + particles from + \param useNormalDirection: If true, the direction of each particle + created will be the normal of the vertex that it's emitting from. The + normal is divided by the normalDirectionModifier parameter, which + defaults to 100.0f. + \param direction: Direction and speed of particle emission. + \param normalDirectionModifier: If the emitter is using the normal + direction then the normal of the vertex that is being emitted from is + divided by this number. + \param mbNumber: This allows you to specify a specific meshBuffer for + the IMesh* to emit particles from. The default value is -1, which + means a random meshBuffer picked from all of the meshes meshBuffers + will be selected to pick a random vertex from. If the value is 0 or + greater, it will only pick random vertices from the meshBuffer + specified by this value. + \param everyMeshVertex: If true, the emitter will emit between min/max + particles every second, for every vertex in the mesh, if false, it will + emit between min/max particles from random vertices in the mesh. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleAnimatedMeshSceneNodeEmitter* createAnimatedMeshSceneNodeEmitter( + scene::IAnimatedMeshSceneNode* node, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.0f,0.0f), + f32 normalDirectionModifier = 100.0f, s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0 ) = 0; + + //! Creates a box particle emitter. + /** \param box: The box for the emitter. + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleBoxEmitter* createBoxEmitter( + const core::aabbox3df& box = core::aabbox3df(-10,28,-10,10,30,10), + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0) = 0; + + //! Creates a particle emitter for emitting from a cylinder + /** \param center: The center of the circle at the base of the cylinder + \param radius: The thickness of the cylinder + \param normal: Direction of the length of the cylinder + \param length: The length of the the cylinder + \param outlineOnly: Whether or not to put points inside the cylinder or + on the outline only + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleCylinderEmitter* createCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly = false, + const core::vector3df& direction = core::vector3df(0.0f,0.0f,0.0f), + u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0 ) = 0; + + //! Creates a mesh particle emitter. + /** \param mesh: Pointer to mesh to emit particles from + \param useNormalDirection: If true, the direction of each particle + created will be the normal of the vertex that it's emitting from. The + normal is divided by the normalDirectionModifier parameter, which + defaults to 100.0f. + \param direction: Direction and speed of particle emission. + \param normalDirectionModifier: If the emitter is using the normal + direction then the normal of the vertex that is being emitted from is + divided by this number. + \param mbNumber: This allows you to specify a specific meshBuffer for + the IMesh* to emit particles from. The default value is -1, which + means a random meshBuffer picked from all of the meshes meshBuffers + will be selected to pick a random vertex from. If the value is 0 or + greater, it will only pick random vertices from the meshBuffer + specified by this value. + \param everyMeshVertex: If true, the emitter will emit between min/max + particles every second, for every vertex in the mesh, if false, it will + emit between min/max particles from random vertices in the mesh. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleMeshEmitter* createMeshEmitter( + scene::IMesh* mesh, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.0f,0.0f), + f32 normalDirectionModifier = 100.0f, s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0 ) = 0; + //! Creates a point particle emitter. - //! \param direction: Direction and speed of particle emission. - //! \param minParticlesPerSecond: Minimal amount of particles emitted - //! per second. - //! \param maxParticlesPerSecond: Maximal amount of particles emitted - //! per second. - //! \param minStartColor: Minimal initial start color of a particle. - //! The real color of every particle is calculated as random interpolation - //! between minStartColor and maxStartColor. - //! \param maxStartColor: Maximal initial start color of a particle. - //! The real color of every particle is calculated as random interpolation - //! between minStartColor and maxStartColor. - //! \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. - //! \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. - //! \param maxAngleDegrees: Maximal angle in degrees, the emitting direction - //! of the particle will differ from the orignial direction. - //! \return Returns a pointer to the created particle emitter. - //! To set this emitter as new emitter of this particle system, - //! just call setEmitter(). Note that you'll have to drop() the - //! returned pointer, after you don't need it any more, see - //! IUnknown::drop() for more informations. - virtual IParticleEmitter* createPointEmitter( + /** \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticlePointEmitter* createPointEmitter( const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, - video::SColor minStartColor = video::SColor(255,0,0,0), - video::SColor maxStartColor = video::SColor(255,255,255,255), + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, s32 maxAngleDegrees=0) = 0; - //! Creates a box particle emitter. - //! \param box: The box for the emitter. - //! \param direction: Direction and speed of particle emission. - //! \param minParticlesPerSecond: Minimal amount of particles emitted - //! per second. - //! \param maxParticlesPerSecond: Maximal amount of particles emitted - //! per second. - //! \param minStartColor: Minimal initial start color of a particle. - //! The real color of every particle is calculated as random interpolation - //! between minStartColor and maxStartColor. - //! \param maxStartColor: Maximal initial start color of a particle. - //! The real color of every particle is calculated as random interpolation - //! between minStartColor and maxStartColor. - //! \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. - //! \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. - //! \param maxAngleDegrees: Maximal angle in degrees, the emitting direction - //! of the particle will differ from the orignial direction. - //! \return Returns a pointer to the created particle emitter. - //! To set this emitter as new emitter of this particle system, - //! just call setEmitter(). Note that you'll have to drop() the - //! returned pointer, after you don't need it any more, see - //! IUnknown::drop() for more informations. - virtual IParticleEmitter* createBoxEmitter( - const core::aabbox3df& box = core::aabbox3df(-10,28,-10,10,30,10), + //! Creates a ring particle emitter. + /** \param center: Center of ring + \param radius: Distance of points from center, points will be rotated + around the Y axis at a random 360 degrees and will then be shifted by + the provided ringThickness values in each axis. + \param ringThickness : thickness of the ring or how wide the ring is + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleRingEmitter* createRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, - video::SColor minStartColor = video::SColor(255,0,0,0), - video::SColor maxStartColor = video::SColor(255,255,255,255), + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, s32 maxAngleDegrees=0) = 0; - //! Creates a fade out particle affector. This affector modifies - //! the color of every particle and and reaches the final color - //! when the particle dies. - //! This affector looks really good, if the EMT_TRANSPARENT_VERTEX_ALPHA - //! material is used and the targetColor is video::SColor(0,0,0,0): - //! Particles are fading out into void with this setting. - //! \param targetColor: Color whereto the color of the particle is changed. - //! \param timeNeededToFadeOut: How much time in milli seconds - //! should the affector need to change the color to the targetColor. - //! \return Returns a pointer to the created particle affector. - //! To add this affector as new affector of this particle system, - //! just call addAffector(). Note that you'll have to drop() the - //! returned pointer, after you don't need it any more, see - //! IUnknown::drop() for more informations. - virtual IParticleAffector* createFadeOutParticleAffector( - video::SColor targetColor = video::SColor(0,0,0,0), + //! Creates a sphere particle emitter. + /** \param center: Center of sphere + \param radius: Radius of sphere + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleSphereEmitter* createSphereEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0) = 0; + + //! Creates a point attraction affector. + /** This affector modifies the positions of the particles and attracts + them to a specified point at a specified speed per second. + \param point: Point to attract particles to. + \param speed: Speed in units per second, to attract to the specified + point. + \param attract: Whether the particles attract or detract from this + point. + \param affectX: Whether or not this will affect the X position of the + particle. + \param affectY: Whether or not this will affect the Y position of the + particle. + \param affectZ: Whether or not this will affect the Z position of the + particle. + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleAttractionAffector* createAttractionAffector( + const core::vector3df& point, f32 speed = 1.0f, bool attract = true, + bool affectX = true, bool affectY = true, bool affectZ = true) = 0; + + //! Creates a fade out particle affector. + /** This affector modifies the color of every particle and and reaches + the final color when the particle dies. This affector looks really + good, if the EMT_TRANSPARENT_VERTEX_ALPHA material is used and the + targetColor is video::SColor(0,0,0,0): Particles are fading out into + void with this setting. + \param targetColor: Color whereto the color of the particle is changed. + \param timeNeededToFadeOut: How much time in milli seconds should the + affector need to change the color to the targetColor. + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleFadeOutAffector* createFadeOutParticleAffector( + const video::SColor& targetColor = video::SColor(0,0,0,0), u32 timeNeededToFadeOut = 1000) = 0; - //! Creates a gravity affector. This affector modifies the direction - //! of the particle. It assumes that the particle is fired out of the - //! emitter with huge force, but is loosing this after some time - //! and is catched by the gravity then. This affector is ideal for - //! creating things like fountains. - //! \param gravity: Direction and force of gravity. - //! \param timeForceLost: Time in milli seconds when the force - //! of the emitter is totally lost and the particle does not move any more. - //! This is the time where gravity fully affects the particle. - //! \return Returns a pointer to the created particle affector. - //! To add this affector as new affector of this particle system, - //! just call addAffector(). Note that you'll have to drop() the - //! returned pointer, after you don't need it any more, see - //! IUnknown::drop() for more informations. - virtual IParticleAffector* createGravityAffector( + //! Creates a gravity affector. + /** This affector modifies the direction of the particle. It assumes + that the particle is fired out of the emitter with huge force, but is + loosing this after some time and is catched by the gravity then. This + affector is ideal for creating things like fountains. + \param gravity: Direction and force of gravity. + \param timeForceLost: Time in milli seconds when the force of the + emitter is totally lost and the particle does not move any more. This + is the time where gravity fully affects the particle. + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleGravityAffector* createGravityAffector( const core::vector3df& gravity = core::vector3df(0.0f,-0.03f,0.0f), u32 timeForceLost = 1000) = 0; + + //! Creates a rotation affector. + /** This affector modifies the positions of the particles and attracts + them to a specified point at a specified speed per second. + \param speed: Rotation in degrees per second + \param pivotPoint: Point to rotate the particles around + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more informations. */ + virtual IParticleRotationAffector* createRotationAffector( + const core::vector3df& speed = core::vector3df(5.0f,5.0f,5.0f), + const core::vector3df& pivotPoint = core::vector3df(0.0f,0.0f,0.0f) ) = 0; }; } // end namespace scene diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/irrArray.h Irrlicht_starsonata/include/irrArray.h --- irrlicht-svn-ss/trunk/include/irrArray.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/irrArray.h 2008-01-04 22:55:52.000000000 +0100 @@ -131,10 +131,14 @@ public: for (u32 i=used; i>0; --i) { //data[i] = data[i-1]; + if ( i 0 ) + allocator.destruct(&data[0]); allocator.construct(&data[0], element); is_sorted = false; @@ -154,11 +158,18 @@ public: if (used + 1 > allocated) reallocate(used +1); - for (u32 i=used++; i>index; --i) + for (u32 i=used; i>index; --i) + { + if ( i index ) + allocator.destruct(&data[index]); allocator.construct(&data[index], element); // data[index] = element; is_sorted = false; + ++used; } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IrrCompileConfig.h Irrlicht_starsonata/include/IrrCompileConfig.h --- irrlicht-svn-ss/trunk/include/IrrCompileConfig.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IrrCompileConfig.h 2008-05-14 05:57:46.000000000 +0200 @@ -224,5 +224,8 @@ precision will be lower but speed higher #undef _IRR_COMPILE_WITH_DIRECT3D_9_ #endif +// enable/disable profiler +#define IRR_PROFILE 1 + #endif // __IRR_COMPILE_CONFIG_H_INCLUDED__ diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IrrlichtDevice.h Irrlicht_starsonata/include/IrrlichtDevice.h --- irrlicht-svn-ss/trunk/include/IrrlichtDevice.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IrrlichtDevice.h 2008-06-24 21:31:18.000000000 +0200 @@ -175,6 +175,29 @@ while(device->run()) //! Sets if the window should be resizeable in windowed mode. /** The default is false. This method only works in windowed mode. */ virtual void setResizeAble(bool resize=false) = 0; + + // starsonata, micha: + //! remove all events pending in the message loop + //! NOTE: This will not remove the WM_QUIT on windows you have to call run() once more to consume that one + virtual void clearPendingEvents() = 0; + + // starsonata, micha: + //! minimize the application. Only supported on windows so far. + virtual void minimize() = 0; + + //! minimize the application. Only supported on windows so far. + virtual void maximize() = 0; + + //! restore mainwindow to original size. Only supported on windows so far. + virtual void restore() = 0; + + // starsonata, micha: + //! Check if application is minimized. Only supported on windows so far. + virtual bool isMinimized() = 0; + + // starsonata, micha: + //! Check if main window is maximized. Only supported on windows so far. + virtual bool isMaximized() = 0; }; } // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/irrlicht.h Irrlicht_starsonata/include/irrlicht.h --- irrlicht-svn-ss/trunk/include/irrlicht.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/irrlicht.h 2008-05-14 05:43:46.000000000 +0200 @@ -63,6 +63,7 @@ #include "IGUIElement.h" #include "IGUIEditBox.h" #include "IGUIEnvironment.h" +#include "IGUIFontFactory.h" #include "IGUIFileOpenDialog.h" #include "IGUIColorSelectDialog.h" #include "IGUIFont.h" @@ -70,6 +71,8 @@ #include "IGUIImage.h" #include "IGUIInOutFader.h" #include "IGUIListBox.h" +#include "IGUITable.h" +#include "Extended_IGUIRectangle.h" #include "IGUIMeshViewer.h" #include "IGUIScrollBar.h" #include "IGUISkin.h" @@ -78,6 +81,7 @@ #include "IGUIWindow.h" #include "IGUIToolbar.h" #include "IGUISpinBox.h" +#include "IGUISpriteBank.h" #include "IImage.h" #include "ILightSceneNode.h" #include "ILogger.h" @@ -139,6 +143,7 @@ #include "SViewFrustum.h" #include "irrTypes.h" #include "coreutil.h" +#include "profiler.h" /*! \mainpage Irrlicht Engine 1.3.1 API documentation * @@ -297,7 +302,6 @@ namespace irr IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx( const SIrrlichtCreationParameters& parameters); - // THE FOLLOWING IS AN EMPTY LIST OF ALL SUB NAMESPACES // EXISTING ONLY FOR THE DOCUMENTATION SOFTWARE DOXYGEN. diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/irrMath.h Irrlicht_starsonata/include/irrMath.h --- irrlicht-svn-ss/trunk/include/irrMath.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/irrMath.h 2007-11-30 08:54:38.000000000 +0100 @@ -116,7 +116,7 @@ namespace core //! point rounding errors into account inline bool equals(const f32 a, const f32 b, const f32 tolerance = ROUNDING_ERROR_32) { - return (a + tolerance > b) && (a - tolerance < b); + return (a + tolerance >= b) && (a - tolerance <= b); } //! returns if a float equals zero, taking floating diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/ITexture.h Irrlicht_starsonata/include/ITexture.h --- irrlicht-svn-ss/trunk/include/ITexture.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/ITexture.h 2008-05-07 18:18:52.000000000 +0200 @@ -62,6 +62,11 @@ enum E_TEXTURE_CREATION_FLAG //! Discard any alpha layer and use non-alpha color format. ETCF_NO_ALPHA_CHANNEL = 0x00000020, + // Starsonata, Micha + //! When textures are not power of two they will usually be scaled. + //! When this flag is set the textures will instead be padded up to the power of two sizes. + ETCF_PAD_NPOT = 0x00000040, + //! This flag is never used, it only forces the compiler to //! compile these enumeration values to 32 bit. ETCF_FORCE_32_BIT_DO_NOT_USE = 0x7fffffff @@ -81,7 +86,7 @@ inline E_TEXTURE_CREATION_FLAG getTextur return ETCF_ALWAYS_32_BIT; if (flags & ETCF_OPTIMIZED_FOR_QUALITY) return ETCF_OPTIMIZED_FOR_QUALITY; - return ETCF_OPTIMIZED_FOR_SPEED; + return ETCF_OPTIMIZED_FOR_QUALITY; } @@ -101,7 +106,6 @@ public: //! constructor ITexture(const c8* name) : Name(name) { - Name.make_lower(); } //! destructor @@ -163,6 +167,10 @@ public: //! Returns name of texture (in most cases this is the filename) const core::stringc& getName() { return Name; } + // starsonata, micha + //! returns if the texture was padded to get power of two sizes + virtual bool hasPaddingForPOT() const { return false; } + protected: core::stringc Name; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IVideoDriver.h Irrlicht_starsonata/include/IVideoDriver.h --- irrlicht-svn-ss/trunk/include/IVideoDriver.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IVideoDriver.h 2008-08-04 00:01:04.000000000 +0200 @@ -424,10 +424,14 @@ namespace video Color(255,255,255,255), the color is ignored. Note that the alpha component is used: If alpha is other than 255, the image will be transparent. \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is - used to draw the image.*/ + used to draw the image. + \param angleInDegree: rotation angle + \param rotationCenter in local coordinates of the texture (if non is set the center of the texture is used) + */ virtual void draw2DImage(video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect = 0, - SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) = 0; + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL) = 0; //! draws a set of 2d images, using a color and the alpha /** channel of the texture if desired. The images are drawn @@ -462,10 +466,14 @@ namespace video \param sourceRect: the rectangle denoting a part of the texture \param clipRect: clips the destination rectangle (may be 0) \param colors: array of 4 colors denoting the color values of the corners of the destRect - \param useAlphaChannelOfTexture: true if alpha channel will be blended. */ + \param useAlphaChannelOfTexture: true if alpha channel will be blended. + \param angleInDegree: rotation angle + \param rotationCenter in local coordinates of the texture (if non is set the center of the texture is used) + */ virtual void draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect = 0, - video::SColor* colors=0, bool useAlphaChannelOfTexture=false) = 0; + video::SColor* colors=0, bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL) = 0; //!Draws an 2d rectangle. /** \param color: Color of the rectangle to draw. The alpha component will not diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/profiler.h Irrlicht_starsonata/include/profiler.h --- irrlicht-svn-ss/trunk/include/profiler.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/include/profiler.h 2008-08-20 14:22:17.000000000 +0200 @@ -0,0 +1,463 @@ +#ifndef __PROFILER_H_INCLUDED__ +#define __PROFILER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "irrTypes.h" +#include "rect.h" +#include "irrString.h" +#include "irrArray.h" +#include "ITimer.h" +#include "IGUIEnvironment.h" +#include "IGUIListbox.h" +#include + +namespace irr +{ +struct ProfileData +{ + friend class Profiler; + + ProfileData() + { + GroupId = 0; + reset(); + } + + bool operator<(const ProfileData& pd) const + { + return Id < pd.Id; + } + +private: + ProfileData(u32 id) : Id(id) {} // just to be used for searching + + void reset() + { + CountCalls = 0; + HighestTime = 0; + LowestTime = UINT_MAX; + TimeSum = 0; + LastTimeStarted = 0; + } + + u32 Id; + u32 GroupId; + core::stringw Name; + + u32 CountCalls; + u32 HighestTime; + u32 LowestTime; + u32 TimeSum; + + u32 LastTimeStarted; +}; + +class Profiler +{ +public: + Profiler() + : IrrTimer(0) + , GuiID(-1) + , DisplayRect(20, 20, 600, 400) + , OverviewGroupId(0) + { + addGroup(OverviewGroupId, "overview"); + ProfileGroups[0].GroupId = UINT_MAX; // overview does not belong to itself so it does not get printed on printAll + CurrentGroupId = OverviewGroupId; + } + + virtual ~Profiler() + { + } + + void init(irr::ITimer * irrlichtTimer, s32 guiId) + { + IrrTimer = irrlichtTimer; + GuiID = guiId; + } + + // set the rectangle used for the display listbox + void setDisplayRect(const core::rect &rect_) + { + DisplayRect = rect_; + } + + inline void add(u32 id_, u32 groupId_, const core::stringw &name_); + inline void addGroup(u32 groupId_, const core::stringw &name_); + + inline void start(u32 id_); + inline void stop(u32 id_); + + inline void reset(u32 id_); + inline void resetGroup(u32 groupId_); + inline void resetAll(); + inline void show(gui::IGUIEnvironment* env_); // print current display group on screen + inline void hide(gui::IGUIEnvironment* env_); + inline void print(core::stringw &ostream, bool suppressUncalled_=true); // write current display group into string + inline void printAll(core::stringw &ostream, bool includeOverview=false,bool suppressUncalled_=true); // write all groups itno string + + inline void setDisplayGroup(u32 groupId_); + inline void nextDisplayGroup(); + inline void previousDisplayGroup(); + inline void firstDisplayGroup(); + +protected: + inline void printGroup(core::stringw &ostream, u32 groupId_, bool suppressUncalled_); + inline core::stringw makeDataString(const ProfileData & data_); + inline core::stringw makeTitleString(); + +private: + irr::ITimer * IrrTimer; + s32 GuiID; + core::rect DisplayRect; + u32 OverviewGroupId; + u32 CurrentGroupId; + core::array ProfileDatas; + core::array ProfileGroups; +}; + +IRRLICHT_API Profiler* IRRCALLCONV getProfiler(); +extern Profiler gPROFILER; + + +// inline implementation +void Profiler::add(u32 id, u32 groupId, const core::stringw &name) +{ + ProfileData data; + data.Id = id; + data.GroupId = groupId; + data.Name = name; + + s32 idx = ProfileDatas.binary_search(data); + if ( idx < 0 ) + { + ProfileDatas.push_back(data); + ProfileDatas.sort(); + } + else + { + ProfileDatas[idx] = data; + } +} + +void Profiler::addGroup(u32 groupId, const core::stringw &name) +{ + ProfileData group; + group.Id = groupId; + group.GroupId = OverviewGroupId; + group.Name = name; + + s32 idx = ProfileGroups.binary_search(group); + if ( idx < 0 ) + { + ProfileGroups.push_back(group); + ProfileGroups.sort(); + } + else + { + ProfileGroups[idx] = group; + } +} + +void Profiler::start(u32 id) +{ + s32 idx = ProfileDatas.binary_search(ProfileData(id)); + if ( idx >= 0 && IrrTimer ) + { + ProfileDatas[idx].LastTimeStarted = IrrTimer->getRealTime(); + } +} + +void Profiler::stop(u32 id) +{ + s32 idx = ProfileDatas.binary_search(ProfileData(id)); + if ( idx >= 0 && IrrTimer ) + { + ProfileData &data = ProfileDatas[idx]; + u32 diffTime = IrrTimer->getRealTime() - data.LastTimeStarted; + if ( data.LastTimeStarted == 0 ) + return; + + ++data.CountCalls; + data.TimeSum += diffTime; + if ( diffTime > data.HighestTime ) + data.HighestTime = diffTime; + if ( diffTime < data.LowestTime ) + data.LowestTime = diffTime; + data.LastTimeStarted = 0; + + + s32 idxGroup = ProfileGroups.binary_search(ProfileData(data.GroupId)); + if ( idxGroup >= 0 ) + { + ProfileData & group = ProfileGroups[idxGroup]; + ++group.CountCalls; + group.TimeSum += diffTime; + if ( diffTime > group.HighestTime ) + group.HighestTime = diffTime; + if ( diffTime < group.LowestTime ) + group.LowestTime = diffTime; + group.LastTimeStarted = 0; + } + } +} + +void Profiler::reset(u32 id) +{ + s32 idx = ProfileDatas.binary_search(ProfileData(id)); + if ( idx >= 0 ) + { + ProfileData &data = ProfileDatas[idx]; + + s32 idxGroup = ProfileGroups.binary_search(ProfileData(data.GroupId)); + if ( idxGroup >= 0 ) + { + ProfileData & group = ProfileGroups[idxGroup]; + group.CountCalls -= data.CountCalls; + group.TimeSum -= data.TimeSum; + } + + data.reset(); + } +} + +void Profiler::resetGroup(u32 groupId) +{ + for ( u32 i=0; iaddListBox(DisplayRect, 0, GuiID, true); + + core::stringw wstrTitle(makeTitleString()); + listBox->addItem(wstrTitle.c_str()); + + s32 idxGroup = ProfileGroups.binary_search(ProfileData(CurrentGroupId)); + if ( idxGroup < 0 ) + return; + + core::stringw wstrGroup(makeDataString(ProfileGroups[idxGroup])); + listBox->addItem(wstrGroup.c_str()); + + // show overview over groups? + if ( CurrentGroupId == OverviewGroupId ) + { + for ( u32 i=0; iaddItem(wstrData.c_str()); + } + } + } + // show data for current group + else + { + for ( u32 i=0; iaddItem(wstrData.c_str()); + } + } + } +} + +void Profiler::hide(irr::gui::IGUIEnvironment* env_) +{ + if ( !env_) + return; + + gui::IGUIElement* root = env_->getRootGUIElement(); + gui::IGUIElement* e = root->getElementFromId(GuiID, true); + if (e) + { + e->remove(); + } +} + +void Profiler::setDisplayGroup(u32 groupId) +{ + CurrentGroupId = groupId; +} + +void Profiler::nextDisplayGroup() +{ + s32 idxGroup = ProfileGroups.binary_search(ProfileData(CurrentGroupId)); + if ( idxGroup < 0 ) + { + CurrentGroupId = 0; + } + else + { + ++idxGroup; + idxGroup %= ProfileGroups.size(); + CurrentGroupId = ProfileGroups[idxGroup].Id; + } +} + +void Profiler::previousDisplayGroup() +{ + s32 idxGroup = ProfileGroups.binary_search(ProfileData(CurrentGroupId)); + if ( idxGroup == 0 ) + { + idxGroup = ProfileGroups.size()-1; + } + else + { + --idxGroup; + } + if ( idxGroup < 0 ) + { + CurrentGroupId = 0; + } + else + { + CurrentGroupId = ProfileGroups[idxGroup].Id; + } +} + +void Profiler::firstDisplayGroup() +{ + if ( !ProfileGroups.size() ) + { + CurrentGroupId = 0; + } + else + { + CurrentGroupId = ProfileGroups[0].Id; + } +} + +// print current active group +void Profiler::print(core::stringw &ostream, bool suppressUncalled) +{ + ostream += makeTitleString(); + printGroup(ostream, CurrentGroupId, suppressUncalled); +} + +void Profiler::printAll(core::stringw &ostream, bool includeOverview, bool suppressUncalled) +{ + ostream += makeTitleString(); + for ( u32 i=0; i 0) + && ProfileGroups[i].GroupId == OverviewGroupId ) + { + ostream += makeDataString(ProfileGroups[i]); + } + } + } + // print all data in a group + else + { + for ( u32 i=0; i 0) + && ProfileDatas[i].GroupId == groupId ) + { + ostream += makeDataString(ProfileDatas[i]); + } + } + } +} + +core::stringw Profiler::makeTitleString() +{ + return core::stringw("name calls time(sum) time(avg) time(max) time(min) \n"); +} + +core::stringw Profiler::makeDataString(const ProfileData & data_) +{ + core::stringw ostr; + + if ( data_.CountCalls > 0 ) + { + // don't we all sometimes dream of stl-streaming in irrlicht? +#ifdef _MSC_VER +#pragma warning(disable:4996) // 'sprintf' was declared deprecated +#endif + char dummy[1023]; + core::stringc name( data_.Name.c_str() ); // not a perfect conversion but don't wanna fight with finding platform independent wide-char printfs now + sprintf(dummy, "%-15.15s%-12u%-12u%-12u%-12u%-12u\n", + name.c_str(), data_.CountCalls, data_.TimeSum, + data_.TimeSum / data_.CountCalls, data_.HighestTime, + (data_.LowestTime <= data_.HighestTime ? data_.LowestTime : 0) + ); + dummy[1022] = 0; + ostr += core::stringw(dummy); +#ifdef _MSC_VER +#pragma warning(default :4996) // 'sprintf' was declared deprecated +#endif + } + else + { + ostr += data_.Name; + ostr += L"\n"; + } + + return ostr; +} + +} // namespace irr + +#if IRR_PROFILE + #define PROFILE_ADD(id_, groupId_, name_) irr::getProfiler()->add(id_, groupId_, name_) + #define PROFILE_ADD_GROUP(groupId_, name_) irr::getProfiler()->addGroup(groupId_, name_) + #define PROFILE_START(id_) irr::getProfiler()->start(id_) + #define PROFILE_STOP(id_) irr::getProfiler()->stop(id_) +#else + #define PROFILE_ADD(id_, groupId_, name_) + #define PROFILE_ADD_GROUP(groupId_, name_) + #define PROFILE_START(id_) + #define PROFILE_STOP(id_) +#endif // IRR_PROFILE + +#endif // __PROFILER_H_INCLUDED__ diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/SColor.h Irrlicht_starsonata/include/SColor.h --- irrlicht-svn-ss/trunk/include/SColor.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/SColor.h 2008-06-13 19:09:30.000000000 +0200 @@ -224,7 +224,7 @@ namespace video //! Sets the alpha component of the Color. The alpha component //! defines how transparent a color should be. //! \param a: Has to be a value between 0 and 255. - //! 0 means not transparent (opaque), 255 means fully transparent. + //! 255 means not transparent (opaque), 0 means fully transparent. inline void setAlpha(u32 a) { color = ((a & 0xff)<<24) | (color & 0x00ffffff); } //! Sets the red component of the Color. diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CAttributeImpl.h Irrlicht_starsonata/source/Irrlicht/CAttributeImpl.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CAttributeImpl.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CAttributeImpl.h 2007-12-28 23:36:02.000000000 +0100 @@ -1899,18 +1899,25 @@ class CStringWArrayAttribute : public IA { public: - CStringWArrayAttribute(const char* name, core::array value) + CStringWArrayAttribute(const char* name, const core::array& value) { Name = name; setArray(value); } + virtual bool isEqualTo(IAttribute* attrib) + { + if ( !attrib || attrib->getType() != EAT_STRINGWARRAY ) + return false; + return Value == static_cast(attrib)->Value; + } + virtual core::array getArray() { return Value; } - virtual void setArray(core::array value) + virtual void setArray(const core::array& value) { Value = value; } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CAttributes.cpp Irrlicht_starsonata/source/Irrlicht/CAttributes.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CAttributes.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CAttributes.cpp 2007-12-28 23:47:18.000000000 +0100 @@ -15,6 +15,8 @@ namespace io CAttributes::CAttributes(video::IVideoDriver* driver) : Driver(driver) +, DefaultAttributes(NULL) +, DefaultAttributeUsage(EDAU_IGNORE) { #ifdef _DEBUG setDebugName("CAttributes"); @@ -28,10 +30,32 @@ CAttributes::~CAttributes() { clear(); + if ( DefaultAttributes ) + DefaultAttributes->drop(); + if (Driver) Driver->drop(); } +void CAttributes::setDefaultAttributes(IAttributes * attrib) +{ + if ( DefaultAttributes ) + DefaultAttributes->drop(); + DefaultAttributes = attrib; + if ( DefaultAttributes ) + DefaultAttributes->grab(); +} + +IAttributes * CAttributes::getDefaultAttributes() +{ + return DefaultAttributes; +} + +// set in which situations default attributes should be used. +void CAttributes::setDefaultAttributeUsage(E_DEFAULT_ATTRIBUTE_USAGE usage) +{ + DefaultAttributeUsage = usage; +} //! Removes all attributes void CAttributes::clear() @@ -249,6 +273,12 @@ IAttribute* CAttributes::getAttributeP(c if (Attributes[i]->Name == attributeName) return Attributes[i]; + if ( DefaultAttributes && + (DefaultAttributeUsage == EDAU_READ_ONLY || DefaultAttributeUsage == EDAU_READ_WRITE) ) + { + return DefaultAttributes->getAttributeP(attributeName); + } + return 0; } @@ -1541,6 +1571,18 @@ void CAttributes::readAttributeFromXML(i } } +bool CAttributes::isEqualToDefaultAttribute(IAttribute* attrib) +{ + if ( !DefaultAttributes ) + return false; + + IAttribute * defaultAttrib = DefaultAttributes->getAttributeP(attrib->Name.c_str()); + if (!defaultAttrib) + return false; + + return attrib->isEqualTo( defaultAttrib ); +} + //! Write these attributes into a xml file bool CAttributes::write(io::IXMLWriter* writer, bool writeXMLHeader) { @@ -1556,6 +1598,9 @@ bool CAttributes::write(io::IXMLWriter* s32 i=0; for (; i<(s32)Attributes.size(); ++i) { + if ( (DefaultAttributeUsage == EDAU_WRITE_ONLY || DefaultAttributeUsage ==EDAU_READ_WRITE) + && isEqualToDefaultAttribute(Attributes[i]) ) + continue; if ( Attributes[i]->getType() == EAT_STRINGWARRAY ) { core::array arraynames, arrayvalues; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CAttributes.h Irrlicht_starsonata/source/Irrlicht/CAttributes.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CAttributes.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CAttributes.h 2007-10-22 18:56:54.000000000 +0200 @@ -17,13 +17,18 @@ namespace video namespace io { -class IAttribute; - //! Implementation of the IAttributes interface class CAttributes : public IAttributes { public: + //! Default attribute values are returned as result when usual attributnames are not found + virtual void setDefaultAttributes(IAttributes * attrib); + virtual IAttributes * getDefaultAttributes(); + + // set in which situations default attributes should be used. + virtual void setDefaultAttributeUsage(E_DEFAULT_ATTRIBUTE_USAGE usage); + CAttributes(video::IVideoDriver* driver=0); ~CAttributes(); @@ -642,86 +647,23 @@ public: //! Sets an attribute as user pointer virtual void setAttribute(s32 index, void* userPointer); + //! get attribute by name + virtual IAttribute* getAttributeP(const c8* attributeName); + protected: void readAttributeFromXML(io::IXMLReader* reader); + bool isEqualToDefaultAttribute(IAttribute* attrib); +private: core::array Attributes; - IAttribute* getAttributeP(const c8* attributeName); - video::IVideoDriver* Driver; -}; - - -class IAttribute : public virtual IUnknown -{ -public: - - virtual ~IAttribute() {}; - - virtual s32 getInt() { return 0; } - virtual f32 getFloat() { return 0; } - virtual video::SColorf getColorf() { return video::SColorf(1.0f,1.0f,1.0f,1.0f); } - virtual video::SColor getColor() { return video::SColor(255,255,255,255); } - virtual core::stringc getString() { return core::stringc(getStringW().c_str()); } - virtual core::stringw getStringW() { return core::stringw(); } - virtual core::array getArray() { return core::array(); }; - virtual bool getBool() { return false; } - virtual void getBinary(void* outdata, s32 maxLength) {}; - virtual core::vector3df getVector() { return core::vector3df(); } - virtual core::position2di getPosition() { return core::position2di(); } - virtual core::rect getRect() { return core::rect(); } - virtual core::quaternion getQuaternion(){ return core::quaternion(); } - virtual core::matrix4 getMatrix() { return core::matrix4(); } - virtual core::triangle3df getTriangle() { return core::triangle3df(); } - virtual core::vector2df getVector2d() { return core::vector2df(); } - virtual core::vector2di getVector2di() { return core::vector2di(); } - virtual core::line2df getLine2d() { return core::line2df(); } - virtual core::line2di getLine2di() { return core::line2di(); } - virtual core::line3df getLine3d() { return core::line3df(); } - virtual core::line3di getLine3di() { return core::line3di(); } - virtual core::dimension2di getDimension2d() { return core::dimension2di(); } - virtual core::aabbox3d getBBox() { return core::aabbox3d(); } - virtual core::plane3df getPlane() { return core::plane3df(); } - - virtual video::ITexture* getTexture() { return 0; } - virtual const char* getEnum() { return 0; } - virtual void* getUserPointer() { return 0; } - - virtual void setInt(s32 intValue) {}; - virtual void setFloat(f32 floatValue) {}; - virtual void setString(const char* text) {}; - virtual void setString(const wchar_t* text){ setString(core::stringc(text).c_str()); }; - virtual void setArray( core::array arr ) {}; - virtual void setColor(video::SColorf color) {}; - virtual void setColor(video::SColor color) {}; - virtual void setBool(bool boolValue) {}; - virtual void setBinary(void* data, s32 maxLenght) {}; - virtual void setVector(core::vector3df v) {}; - virtual void setPosition(core::position2di v) {}; - virtual void setRect(core::rect v) {}; - virtual void setQuaternion(core::quaternion v) {}; - virtual void setMatrix(core::matrix4 v) {}; - virtual void setTriangle(core::triangle3df v) {}; - virtual void setVector2d(core::vector2df v) {}; - virtual void setVector2d(core::vector2di v) {}; - virtual void setLine2d(core::line2df v) {}; - virtual void setLine2d(core::line2di v) {}; - virtual void setLine3d(core::line3df v) {}; - virtual void setLine3d(core::line3di v) {}; - virtual void setDimension2d(core::dimension2di v) {}; - virtual void setBBox(core::aabbox3d v) {}; - virtual void setPlane(core::plane3df v) {}; - virtual void setUserPointer(void* v) {}; - - virtual void setEnum(const char* enumValue, const char* const* enumerationLiterals) {}; - virtual void setTexture(video::ITexture*) {}; - core::stringc Name; + // MICHA, STARSONATA + IAttributes * DefaultAttributes; + E_DEFAULT_ATTRIBUTE_USAGE DefaultAttributeUsage; - virtual E_ATTRIBUTE_TYPE getType() const = 0; - virtual const wchar_t* getTypeString() const = 0; }; } // end namespace io diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Driver.cpp Irrlicht_starsonata/source/Irrlicht/CD3D8Driver.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Driver.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D8Driver.cpp 2008-08-05 02:03:58.000000000 +0200 @@ -878,7 +878,8 @@ void CD3D8Driver::drawVertexPrimitiveLis void CD3D8Driver::draw2DImage(video::ITexture* texture, const core::position2d& pos, const core::rect& sourceRect, const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) + bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { if (!texture) return; @@ -976,12 +977,16 @@ void CD3D8Driver::draw2DImage(video::ITe s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); f32 yFact = 1.0f / (renderTargetSize.Height>>1); - const core::dimension2d sourceSurfaceSize = texture->getOriginalSize(); + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); core::rect tcoords; - tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)+0.5f) / texture->getOriginalSize().Width ; - tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)+0.5f) / texture->getOriginalSize().Height; - tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / texture->getOriginalSize().Width; - tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / texture->getOriginalSize().Height; + tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)+0.5f) / ss.Width ; + tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)+0.5f) / ss.Height; + tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / ss.Width; + tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / ss.Height; core::rect poss(targetPos, sourceSize); @@ -997,34 +1002,100 @@ void CD3D8Driver::draw2DImage(video::ITe setVertexShader(EVT_STANDARD); + if ( angleInDegree != 0.f ) + { + f32 cx = (vtx[0].Pos.X + vtx[2].Pos.X) / 2; + f32 cy = (vtx[0].Pos.Y + vtx[2].Pos.Y) / 2; + + if ( rotationCenter ) + { + cx = vtx[0].Pos.X + ((f32)rotationCenter->X / (f32)texture->getSize().Width)* (vtx[2].Pos.X - vtx[0].Pos.X); + cy = vtx[0].Pos.Y + ((f32)rotationCenter->Y / (f32)texture->getSize().Height)* (vtx[2].Pos.Y - vtx[0].Pos.Y); + } + + D3DXMATRIX mtrans1; + D3DXMATRIX mRotation; + D3DXMATRIX mtrans2; + D3DXMATRIX mAllTogetherNow; + + D3DXMatrixTranslation( &mtrans1, cx, cy, 0.f ); + D3DXMatrixRotationZ( &mRotation, D3DXToRadian( angleInDegree ) ); + D3DXMatrixTranslation( &mtrans2, -cx, -cy, 0.f ); + + // This is a real bad hack to avoid trouble with the projection matrix. + // I tried to fix it otherwise, but when doing that I break some other part of Irrlicht. + // I suppose it won't be a problem anymore with newer Irrlicht versions and as evil + // as this hack is here - it works. + D3DXMATRIX mScale; + float hackhackhack=float(renderTargetSize.Width)/float(renderTargetSize.Height); + D3DXMatrixScaling(&mScale, 1.0, hackhackhack, 1.0); + + mAllTogetherNow = mtrans2 * mRotation * mScale * mtrans1; + + pID3DDevice->SetTransform( D3DTS_WORLD, &mAllTogetherNow ); + } + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex)); + + if ( angleInDegree != 0.f ) + { + core::matrix4 mat; + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer())); + } } void CD3D8Driver::draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect, - video::SColor* colors, bool useAlphaChannelOfTexture) + video::SColor* colors, bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { if(!texture) return; - const core::dimension2d& ss = texture->getOriginalSize(); + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); core::rect tcoords; tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width; tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height; tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width; tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height; + // clip + core::rect clippedRect(destRect); + if ( clipRect ) + { + clippedRect.clipAgainst(*clipRect); + + // tcoords must be clipped by the same factors + core::rect tcoordsOrig(tcoords); + + f32 fac = f32(clippedRect.UpperLeftCorner.X - destRect.UpperLeftCorner.X) / f32(destRect.getWidth()); + tcoords.UpperLeftCorner.X += fac * (f32)tcoordsOrig.getWidth(); + + fac = f32(destRect.LowerRightCorner.X - clippedRect.LowerRightCorner.X) / f32(destRect.getWidth()); + tcoords.LowerRightCorner.X -= fac * (f32)tcoordsOrig.getWidth(); + + fac = f32(clippedRect.UpperLeftCorner.Y - destRect.UpperLeftCorner.Y) / f32(destRect.getHeight()); + tcoords.UpperLeftCorner.Y += fac * (f32)tcoordsOrig.getHeight(); + + fac = f32(destRect.LowerRightCorner.Y - clippedRect.LowerRightCorner.Y) / f32(destRect.getHeight()); + tcoords.LowerRightCorner.Y -= fac * (f32)tcoordsOrig.getHeight(); + } + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); core::rect npos; f32 xFact = 2.0f / ( renderTargetSize.Width ); f32 yFact = 2.0f / ( renderTargetSize.Height ); - npos.UpperLeftCorner.X = ( destRect.UpperLeftCorner.X * xFact ) - 1.0f; - npos.UpperLeftCorner.Y = 1.0f - ( destRect.UpperLeftCorner.Y * yFact ); - npos.LowerRightCorner.X = ( destRect.LowerRightCorner.X * xFact ) - 1.0f; - npos.LowerRightCorner.Y = 1.0f - ( destRect.LowerRightCorner.Y * yFact ); + npos.UpperLeftCorner.X = ( clippedRect.UpperLeftCorner.X * xFact ) - 1.0f; + npos.UpperLeftCorner.Y = 1.0f - ( clippedRect.UpperLeftCorner.Y * yFact ); + npos.LowerRightCorner.X = ( clippedRect.LowerRightCorner.X * xFact ) - 1.0f; + npos.LowerRightCorner.Y = 1.0f - ( clippedRect.LowerRightCorner.Y * yFact ); video::SColor temp[4] = { @@ -1050,8 +1121,47 @@ void CD3D8Driver::draw2DImage(video::ITe setVertexShader(EVT_STANDARD); + if ( angleInDegree != 0.f ) + { + f32 cx = (vtx[0].Pos.X + vtx[2].Pos.X) / 2; + f32 cy = (vtx[0].Pos.Y + vtx[2].Pos.Y) / 2; + + if ( rotationCenter ) + { + cx = vtx[0].Pos.X + ((f32)rotationCenter->X / (f32)texture->getSize().Width)* (vtx[2].Pos.X - vtx[0].Pos.X); + cy = vtx[0].Pos.Y + ((f32)rotationCenter->Y / (f32)texture->getSize().Height)* (vtx[2].Pos.Y - vtx[0].Pos.Y); + } + + D3DXMATRIX mtrans1; + D3DXMATRIX mRotation; + D3DXMATRIX mtrans2; + D3DXMATRIX mAllTogetherNow; + + D3DXMatrixTranslation( &mtrans1, cx, cy, 0.f ); + D3DXMatrixRotationZ( &mRotation, D3DXToRadian( angleInDegree ) ); + D3DXMatrixTranslation( &mtrans2, -cx, -cy, 0.f ); + + // This is a real bad hack to avoid trouble with the projection matrix. + // I tried to fix it otherwise, but when doing that I break some other part of Irrlicht. + // I suppose it won't be a problem anymore with newer Irrlicht versions and as evil + // as this hack is here - it works. + D3DXMATRIX mScale; + float hackhackhack=float(renderTargetSize.Width)/float(renderTargetSize.Height); + D3DXMatrixScaling(&mScale, 1.0, hackhackhack, 1.0); + + mAllTogetherNow = mtrans2 * mRotation * mScale * mtrans1; + + pID3DDevice->SetTransform( D3DTS_WORLD, &mAllTogetherNow ); + } + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex)); + + if ( angleInDegree != 0.f ) + { + core::matrix4 mat; + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer())); + } } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Driver.h Irrlicht_starsonata/source/Irrlicht/CD3D8Driver.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Driver.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D8Driver.h 2008-08-04 00:03:20.000000000 +0200 @@ -71,12 +71,14 @@ namespace video //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. virtual void draw2DImage(video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect = 0, - SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //! Draws a part of the texture into the rectangle. virtual void draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect = 0, - video::SColor* colors=0, bool useAlphaChannelOfTexture=false); + video::SColor* colors=0, bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //!Draws an 2d rectangle with a gradient. virtual void draw2DRectangle(const core::rect& pos, diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Texture.cpp Irrlicht_starsonata/source/Irrlicht/CD3D8Texture.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Texture.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D8Texture.cpp 2008-05-08 01:04:46.000000000 +0200 @@ -35,6 +35,7 @@ CD3D8Texture::CD3D8Texture(CD3D8Driver* : ITexture(name), Image(0), Texture(0), RTTSurface(0), Driver(driver), TextureSize(size), ImageSize(size), Pitch(0), HasMipMaps(false), IsRenderTarget(true) + , HasPaddingForPOT(false) { #ifdef _DEBUG setDebugName("CD3D8Texture"); @@ -54,6 +55,7 @@ CD3D8Texture::CD3D8Texture(IImage* image : ITexture(name), Image(image), Texture(0), RTTSurface(0), Driver(driver), TextureSize(0,0), ImageSize(0,0), Pitch(0), HasMipMaps(false), IsRenderTarget(false) +, HasPaddingForPOT(false) { #ifdef _DEBUG setDebugName("CD3D8Texture"); @@ -120,9 +122,10 @@ bool CD3D8Texture::createTexture(u32 fla core::dimension2d optSize; ImageSize = Image->getDimension(); - if (Driver->queryFeature(EVDF_TEXTURE_NPOT)) - optSize=ImageSize; - else + // TEST to find problems with cards which don't have this feature + //if (Driver->queryFeature(EVDF_TEXTURE_NPOT)) + // optSize=ImageSize; + //else { optSize.Width = getTextureSizeFromImageSize(ImageSize.Width); optSize.Height = getTextureSizeFromImageSize(ImageSize.Height); @@ -208,7 +211,19 @@ bool CD3D8Texture::copyTexture() } Pitch = rect.Pitch; + + if ( (TextureSize.Width != Image->getDimension().Width + || TextureSize.Height != Image->getDimension().Height) + && Driver->getTextureCreationFlag(ETCF_PAD_NPOT) ) + { + Image->copyTo(rect.pBits, TextureSize.Width, TextureSize.Height, ColorFormat, Pitch); + HasPaddingForPOT = true; + } + else + { + HasPaddingForPOT = false; Image->copyToScaling(rect.pBits, TextureSize.Width, TextureSize.Height, ColorFormat, Pitch); + } hr = Texture->UnlockRect(0); if (FAILED(hr)) diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Texture.h Irrlicht_starsonata/source/Irrlicht/CD3D8Texture.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D8Texture.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D8Texture.h 2008-05-07 05:13:52.000000000 +0200 @@ -73,6 +73,10 @@ public: //! Returns pointer to the render target surface IDirect3DSurface8* getRenderTargetSurface(); + // starsonata, micha + //! returns if the texture was padded to get power of two sizes + virtual bool hasPaddingForPOT() const { return HasPaddingForPOT; } + private: void createRenderTarget(); @@ -108,6 +112,7 @@ private: ECOLOR_FORMAT ColorFormat; bool HasMipMaps; bool IsRenderTarget; + bool HasPaddingForPOT; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Driver.cpp Irrlicht_starsonata/source/Irrlicht/CD3D9Driver.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Driver.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D9Driver.cpp 2008-08-05 02:00:58.000000000 +0200 @@ -870,12 +870,18 @@ void CD3D9Driver::drawVertexPrimitiveLis void CD3D9Driver::draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect, - video::SColor* colors, bool useAlphaChannelOfTexture) + video::SColor* colors, bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { if(!texture) return; - const core::dimension2d& ss = texture->getOriginalSize(); + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); + core::rect tcoords; tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width; tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height; @@ -915,9 +921,71 @@ void CD3D9Driver::draw2DImage(video::ITe setVertexShader(EVT_STANDARD); + // clip + RECT oldScissorRect; + DWORD oldScissorTestRenderState; + if ( clipRect ) + { + pID3DDevice->GetScissorRect(&oldScissorRect); + pID3DDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &oldScissorTestRenderState); + pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + + RECT scissor; + scissor.left = clipRect->UpperLeftCorner.X; + scissor.top = clipRect->UpperLeftCorner.Y; + scissor.right = clipRect->LowerRightCorner.X; + scissor.bottom = clipRect->LowerRightCorner.Y; + pID3DDevice->SetScissorRect(&scissor); + } + + if ( angleInDegree != 0.f ) + { + f32 cx = (vtx[0].Pos.X + vtx[2].Pos.X) / 2; + f32 cy = (vtx[0].Pos.Y + vtx[2].Pos.Y) / 2; + + if ( rotationCenter ) + { + cx = vtx[0].Pos.X + ((f32)rotationCenter->X / (f32)texture->getSize().Width)* (vtx[2].Pos.X - vtx[0].Pos.X); + cy = vtx[0].Pos.Y + ((f32)rotationCenter->Y / (f32)texture->getSize().Height)* (vtx[2].Pos.Y - vtx[0].Pos.Y); + } + + D3DXMATRIX mtrans1; + D3DXMATRIX mRotation; + D3DXMATRIX mtrans2; + D3DXMATRIX mAllTogetherNow; + + D3DXMatrixTranslation( &mtrans1, cx, cy, 0.f ); + + // This is a real bad hack to avoid trouble with the projection matrix. + // I tried to fix it otherwise, but when doing that I break some other part of Irrlicht. + // I suppose it won't be a problem anymore with newer Irrlicht versions and as evil + // as this hack is here - it works. + D3DXMATRIX mScale; + float hackhackhack=float(renderTargetSize.Width)/float(renderTargetSize.Height); + D3DXMatrixScaling(&mScale, 1.0, hackhackhack, 1.0); + + D3DXMatrixRotationZ( &mRotation, D3DXToRadian( angleInDegree ) ); + D3DXMatrixTranslation( &mtrans2, -cx, -cy, 0.f ); + + mAllTogetherNow = mtrans2 * mRotation * mScale * mtrans1; + + pID3DDevice->SetTransform( D3DTS_WORLD, &mAllTogetherNow ); + } + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex)); + if ( angleInDegree != 0.f ) + { + core::matrix4 mat; + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer())); + } + + if ( clipRect ) + { + pID3DDevice->SetScissorRect(&oldScissorRect); + pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, oldScissorTestRenderState); + } } @@ -928,7 +996,8 @@ void CD3D9Driver::draw2DImage(video::ITe const core::position2d& pos, const core::rect& sourceRect, const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) + bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { if (!texture) return; @@ -1027,11 +1096,17 @@ void CD3D9Driver::draw2DImage(video::ITe f32 yPlus = renderTargetSize.Height-(renderTargetSize.Height / 2.f); f32 yFact = 1.0f / (renderTargetSize.Height / 2.f); + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); + core::rect tcoords; - tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)+0.5f) / texture->getOriginalSize().Width ; - tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)+0.5f) / texture->getOriginalSize().Height; - tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / texture->getOriginalSize().Width; - tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / texture->getOriginalSize().Height; + tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)+0.5f) / ss.Width ; + tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)+0.5f) / ss.Height; + tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / ss.Width; + tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / ss.Height; core::rect poss(targetPos, sourceSize); @@ -1047,8 +1122,48 @@ void CD3D9Driver::draw2DImage(video::ITe setVertexShader(EVT_STANDARD); + if ( angleInDegree != 0.f ) + { + f32 cx = (vtx[0].Pos.X + vtx[2].Pos.X) / 2; + f32 cy = (vtx[0].Pos.Y + vtx[2].Pos.Y) / 2; + + if ( rotationCenter ) + { + cx = vtx[0].Pos.X + ((f32)rotationCenter->X / (f32)texture->getSize().Width)* (vtx[2].Pos.X - vtx[0].Pos.X); + cy = vtx[0].Pos.Y + ((f32)rotationCenter->Y / (f32)texture->getSize().Height)* (vtx[2].Pos.Y - vtx[0].Pos.Y); + } + + D3DXMATRIX mtrans1; + D3DXMATRIX mRotation; + D3DXMATRIX mtrans2; + D3DXMATRIX mAllTogetherNow; + + D3DXMatrixTranslation( &mtrans1, cx, cy, 0.f ); + + // This is a real bad hack to avoid trouble with the projection matrix. + // I tried to fix it otherwise, but when doing that I break some other part of Irrlicht. + // I suppose it won't be a problem anymore with newer Irrlicht versions and as evil + // as this hack is here - it works. + D3DXMATRIX mScale; + float hackhackhack=float(renderTargetSize.Width)/float(renderTargetSize.Height); + D3DXMatrixScaling(&mScale, 1.0, hackhackhack, 1.0); + + D3DXMatrixRotationZ( &mRotation, D3DXToRadian( angleInDegree ) ); + D3DXMatrixTranslation( &mtrans2, -cx, -cy, 0.f ); + + mAllTogetherNow = mtrans2 * mRotation * mScale * mtrans1; + + pID3DDevice->SetTransform( D3DTS_WORLD, &mAllTogetherNow ); + } + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex)); + + if ( angleInDegree != 0.f ) + { + core::matrix4 mat; + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer())); + } } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Driver.h Irrlicht_starsonata/source/Irrlicht/CD3D9Driver.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Driver.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D9Driver.h 2008-08-04 00:03:42.000000000 +0200 @@ -65,12 +65,14 @@ namespace video //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. virtual void draw2DImage(video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect = 0, - SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //! Draws a part of the texture into the rectangle. virtual void draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect = 0, - video::SColor* colors=0, bool useAlphaChannelOfTexture=false); + video::SColor* colors=0, bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //!Draws an 2d rectangle with a gradient. virtual void draw2DRectangle(const core::rect& pos, diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Texture.cpp Irrlicht_starsonata/source/Irrlicht/CD3D9Texture.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Texture.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D9Texture.cpp 2008-05-08 01:06:28.000000000 +0200 @@ -34,6 +34,7 @@ CD3D9Texture::CD3D9Texture(CD3D9Driver* : ITexture(name), Image(0), Texture(0), RTTSurface(0), Driver(driver), TextureSize(size), ImageSize(size), Pitch(0), HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(true) + , HasPaddingForPOT(false) { #ifdef _DEBUG setDebugName("CD3D9Texture"); @@ -53,6 +54,7 @@ CD3D9Texture::CD3D9Texture(IImage* image : ITexture(name), Image(image), Texture(0), RTTSurface(0), Driver(driver), TextureSize(0,0), ImageSize(0,0), Pitch(0), HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(false) +, HasPaddingForPOT(false) { #ifdef _DEBUG setDebugName("CD3D9Texture"); @@ -265,9 +267,10 @@ bool CD3D9Texture::createTexture(u32 fla core::dimension2d optSize; ImageSize = Image->getDimension(); - if (Driver->queryFeature(EVDF_TEXTURE_NPOT)) - optSize=ImageSize; - else + // TEST to find problems with cards which don't have this feature + //if (Driver->queryFeature(EVDF_TEXTURE_NPOT)) + // optSize=ImageSize; + //else { optSize.Width = getTextureSizeFromImageSize(ImageSize.Width); optSize.Height = getTextureSizeFromImageSize(ImageSize.Height); @@ -410,7 +413,20 @@ bool CD3D9Texture::copyTexture() } Pitch = rect.Pitch; + + + if ( (TextureSize.Width != Image->getDimension().Width + || TextureSize.Height != Image->getDimension().Height) + && Driver->getTextureCreationFlag(ETCF_PAD_NPOT) ) + { + Image->copyTo(rect.pBits, TextureSize.Width, TextureSize.Height, ColorFormat, Pitch); + HasPaddingForPOT = true; + } + else + { + HasPaddingForPOT = false; Image->copyToScaling(rect.pBits, TextureSize.Width, TextureSize.Height, ColorFormat, Pitch); + } hr = Texture->UnlockRect(0); if (FAILED(hr)) diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Texture.h Irrlicht_starsonata/source/Irrlicht/CD3D9Texture.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CD3D9Texture.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CD3D9Texture.h 2008-05-07 05:14:00.000000000 +0200 @@ -72,6 +72,10 @@ public: //! Returns pointer to the render target surface IDirect3DSurface9* getRenderTargetSurface(); + // starsonata, micha + //! returns if the texture was padded to get power of two sizes + virtual bool hasPaddingForPOT() const { return HasPaddingForPOT; } + private: void createRenderTarget(); @@ -115,6 +119,7 @@ private: bool HasMipMaps; bool HardwareMipMaps; bool IsRenderTarget; + bool HasPaddingForPOT; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CDefaultGUIElementFactory.cpp Irrlicht_starsonata/source/Irrlicht/CDefaultGUIElementFactory.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CDefaultGUIElementFactory.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CDefaultGUIElementFactory.cpp 2007-10-22 18:56:54.000000000 +0200 @@ -21,6 +21,8 @@ #include "IGUITabControl.h" #include "IGUIToolbar.h" #include "IGUIWindow.h" +#include "Extended_IGUIRectangle.h" +#include "IGUITable.h" #include @@ -60,7 +62,7 @@ IGUIElement* CDefaultGUIElementFactory:: case EGUIET_MENU: return Environment->addMenu(parent); case EGUIET_EDIT_BOX: - return Environment->addEditBox(0,core::rect(0,0,100,100),true, parent); + return Environment->addEditBox(0,core::rect(0,0,100,100),true, false, parent); case EGUIET_FILE_OPEN_DIALOG: return Environment->addFileOpenDialog(0,true,parent); case EGUIET_IMAGE: @@ -86,9 +88,14 @@ IGUIElement* CDefaultGUIElementFactory:: case EGUIET_TOOL_BAR: return Environment->addToolBar(parent); case EGUIET_WINDOW: - return Environment->addWindow(core::rect(0,0,100,100),false,0,parent); + return Environment->addWindow(core::rect(0,0,100,100),false,0,EWF_CLOSE|EWF_TITLEBAR,parent); case EGUIET_SPIN_BOX: return Environment->addSpinBox(L"0.0", core::rect(0,0,100,100), parent); + + case EGUIET_TABLE: + return Environment->addTable(core::rect(0,0,100,100), parent); + case EGUIET_RECTANGLE: + return Environment->addRectangle(core::rect(0,0,100,100), parent); } return 0; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CDefaultGUIElementFactory.h Irrlicht_starsonata/source/Irrlicht/CDefaultGUIElementFactory.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CDefaultGUIElementFactory.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CDefaultGUIElementFactory.h 2007-10-22 18:56:54.000000000 +0200 @@ -51,9 +51,10 @@ namespace gui \return: Returns name of the type if this factory can create the type, otherwise 0. */ virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type); - private: + //! get the typenumber for the elementname + virtual EGUI_ELEMENT_TYPE getTypeFromName(const c8* name); - EGUI_ELEMENT_TYPE getTypeFromName(const c8* name); + private: IGUIEnvironment* Environment; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIButton.cpp Irrlicht_starsonata/source/Irrlicht/CGUIButton.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIButton.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIButton.cpp 2008-06-04 02:58:04.000000000 +0200 @@ -18,9 +18,11 @@ namespace gui CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, bool noclip) : IGUIButton(environment, parent, id, rectangle), Pressed(false), - IsPushButton(false), UseAlphaChannel(false), Border(true), - MouseOverTime(0), FocusTime(0), ClickTime(0), SpriteBank(0), - OverrideFont(0), Image(0), PressedImage(0) + IsPushButton(false), UseAlphaChannel(false), + IsFlashing(false), Border(true), ClickTime(0), + ClickShiftState(false), ClickControlState(false), + SpriteBank(0), OverrideFont(0), EnabledOverrideTextColor(false), + Image(0), PressedImage(0), DisabledImage(0) { #ifdef _DEBUG setDebugName("CGUIButton"); @@ -47,6 +49,9 @@ CGUIButton::~CGUIButton() if (Image) Image->drop(); + if ( DisabledImage ) + DisabledImage->drop(); + if (PressedImage) PressedImage->drop(); @@ -89,7 +94,7 @@ void CGUIButton::setSprite(EGUI_BUTTON_S bool CGUIButton::OnEvent(SEvent event) { if (!IsEnabled) - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); switch(event.EventType) { @@ -101,7 +106,18 @@ bool CGUIButton::OnEvent(SEvent event) if (!IsPushButton) setPressed(true); else + { setPressed(!Pressed); + if ( Parent ) + { + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_PUSHBUTTON_STATE_CHANGED; + Parent->OnEvent(newEvent); + } + } return true; } @@ -122,6 +138,9 @@ bool CGUIButton::OnEvent(SEvent event) if (Parent) { + ClickShiftState = false; + ClickControlState = false; + SEvent newEvent; newEvent.EventType = EET_GUI_EVENT; newEvent.GUIEvent.Caller = this; @@ -173,11 +192,23 @@ bool CGUIButton::OnEvent(SEvent event) else { setPressed(!Pressed); + if ( Parent ) + { + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_PUSHBUTTON_STATE_CHANGED; + Parent->OnEvent(newEvent); + } } if ((!IsPushButton && wasPressed && Parent) || (IsPushButton && wasPressed != Pressed)) { + ClickShiftState = event.MouseInput.Shift; + ClickControlState = event.MouseInput.Control; + SEvent newEvent; newEvent.EventType = EET_GUI_EVENT; newEvent.GUIEvent.Caller = this; @@ -191,7 +222,7 @@ bool CGUIButton::OnEvent(SEvent event) break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } @@ -205,12 +236,11 @@ void CGUIButton::draw() IGUISkin* skin = Environment->getSkin(); irr::video::IVideoDriver* driver = Environment->getVideoDriver(); - IGUIFont* font = OverrideFont; - if (!OverrideFont) - font = skin->getFont(EGDF_BUTTON); + IGUIFont* font = getCurrentFont(); core::rect rect = AbsoluteRect; + // todo (MICHA): lot of duplicated code here. One call to draw2DImage and one to draw2DSprite would be cleaner imho. // todo: move sprite up and text down if the pressed state has a sprite // draw sprites for focused and mouse-over core::position2di spritePos = AbsoluteRect.getCenter(); @@ -218,9 +248,26 @@ void CGUIButton::draw() if (!Pressed) { if (Border) - skin->draw3DButtonPaneStandard(this, rect, &AbsoluteClippingRect); + { + u32 flashFrequency=0; + u32 flashTime=os::Timer::getTime(); + if ( IsFlashing ) + { + flashFrequency = 1000; + } + skin->draw3DButtonPaneStandard(this, rect, &AbsoluteClippingRect, flashFrequency, flashTime); + } - if (Image) + if ( !isEnabled() && DisabledImage ) + { + core::position2d pos = AbsoluteRect.getCenter(); + pos.X -= DisabledImageRect.getWidth() / 2; + pos.Y -= DisabledImageRect.getHeight() / 2; + + driver->draw2DImage(DisabledImage, pos, DisabledImageRect, &AbsoluteClippingRect, + video::SColor(255,255,255,255), UseAlphaChannel); + } + else if (Image) { core::position2d pos = AbsoluteRect.getCenter(); pos.X -= ImageRect.getWidth() / 2; @@ -231,7 +278,7 @@ void CGUIButton::draw() } if (SpriteBank && ButtonSprites[EGBS_BUTTON_UP].Index != -1) { - // draw pressed sprite + // draw sprite SpriteBank->draw2DSprite(ButtonSprites[EGBS_BUTTON_UP].Index, spritePos, &AbsoluteClippingRect, ButtonSprites[EGBS_BUTTON_UP].Color, ClickTime, os::Timer::getTime(), ButtonSprites[EGBS_BUTTON_UP].Loop, true); @@ -240,9 +287,26 @@ void CGUIButton::draw() else { if (Border) - skin->draw3DButtonPanePressed(this, rect, &AbsoluteClippingRect); + { + u32 flashFrequency=0; + u32 flashTime=os::Timer::getTime(); + if ( IsFlashing ) + { + flashFrequency = 1000; + } + skin->draw3DButtonPanePressed(this, rect, &AbsoluteClippingRect, flashFrequency, flashTime); + } - if (PressedImage) + if ( !isEnabled() && DisabledImage ) + { + core::position2d pos = AbsoluteRect.getCenter(); + pos.X -= DisabledImageRect.getWidth() / 2; + pos.Y -= DisabledImageRect.getHeight() / 2; + + driver->draw2DImage(DisabledImage, pos, DisabledImageRect, &AbsoluteClippingRect, + video::SColor(255,255,255,255), UseAlphaChannel); + } + else if (PressedImage) { core::position2d pos = AbsoluteRect.getCenter(); pos.X -= PressedImageRect.getWidth() / 2; @@ -259,7 +323,7 @@ void CGUIButton::draw() if (SpriteBank && ButtonSprites[EGBS_BUTTON_DOWN].Index != -1) { - // draw sprite + // draw pressed sprite SpriteBank->draw2DSprite(ButtonSprites[EGBS_BUTTON_DOWN].Index, spritePos, &AbsoluteClippingRect, ButtonSprites[EGBS_BUTTON_DOWN].Color, ClickTime, os::Timer::getTime(), ButtonSprites[EGBS_BUTTON_DOWN].Loop, true); @@ -274,10 +338,21 @@ void CGUIButton::draw() rect.UpperLeftCorner.Y += 2; if (font) + { + video::SColor textColor; + if ( EnabledOverrideTextColor ) + textColor = OverrideTextColor; + else if ( IsEnabled ) + textColor = skin->getColor(EGDC_BUTTON_TEXT); + else + textColor = skin->getColor(EGDC_GRAY_TEXT); + + font->draw(Text.c_str(), rect, - skin->getColor(IsEnabled ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), true, true, + textColor, true, true, &AbsoluteClippingRect); } + } IGUIElement::draw(); } @@ -287,6 +362,9 @@ void CGUIButton::draw() //! sets another skin independent font. if this is set to zero, the button uses the font of the skin. void CGUIButton::setOverrideFont(IGUIFont* font) { + if ( OverrideFont == font ) + return; + if (OverrideFont) OverrideFont->drop(); @@ -296,19 +374,30 @@ void CGUIButton::setOverrideFont(IGUIFon OverrideFont->grab(); } +IGUIFont* CGUIButton::getCurrentFont() +{ + if ( OverrideFont ) + return OverrideFont; + + return Environment->getSkin()->getFont(EGDF_BUTTON); +} + //! Sets an image which should be displayed on the button when it is in normal state. void CGUIButton::setImage(video::ITexture* image) { + if ( image != Image ) + { if (Image) Image->drop(); Image = image; - if (image) - ImageRect = core::rect(core::position2d(0,0), image->getOriginalSize()); if (Image) Image->grab(); + } + if (image) + ImageRect = core::rect(core::position2d(0,0), image->getOriginalSize()); if (!PressedImage) setPressedImage(Image); @@ -317,14 +406,17 @@ void CGUIButton::setImage(video::ITextur //! Sets an image which should be displayed on the button when it is in normal state. void CGUIButton::setImage(video::ITexture* image, const core::rect& pos) { + ImageRect = pos; + if ( Image != image ) + { if (Image) Image->drop(); Image = image; - ImageRect = pos; if (Image) Image->grab(); + } if (!PressedImage) setPressedImage(Image, pos); @@ -357,6 +449,36 @@ void CGUIButton::setPressedImage(video:: PressedImage->grab(); } +//! Sets the background image which should be displayed on the button when it is in disabled state. +/** \param image: Image to be displayed */ +void CGUIButton::setDisabledImage(video::ITexture* image) +{ + if (DisabledImage) + DisabledImage->drop(); + + DisabledImage = image; + if (image) + DisabledImageRect = core::rect(core::position2d(0,0), image->getOriginalSize()); + + if (DisabledImage) + DisabledImage->grab(); +} + +//! Sets the background image which should be displayed on the button when it is in disabled state. +/** \param image: Texture containing the image to be displayed + \param pos: Position in the texture, where the image is located */ +void CGUIButton::setDisabledImage(video::ITexture* image, const core::rect& pos) +{ + if (DisabledImage) + DisabledImage->drop(); + + DisabledImage = image; + DisabledImageRect = pos; + + if (DisabledImage) + DisabledImage->grab(); +} + //! Sets if the button should behave like a push button. Which means it //! can be in two states: Normal or Pressed. With a click on the button, @@ -410,6 +532,26 @@ bool CGUIButton::isDrawingBorder() return Border; } +void CGUIButton::setFlashing(bool flash_) +{ + IsFlashing = flash_; +} + +bool CGUIButton::isFlashing() const +{ + return IsFlashing; +} + +void CGUIButton::setOverrideTextColor( video::SColor color ) +{ + OverrideTextColor = color; +} + +void CGUIButton::enableOverrideTextColor(bool enable) +{ + EnabledOverrideTextColor = enable; +} + //! Writes attributes of the element. void CGUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) { @@ -424,11 +566,18 @@ void CGUIButton::serializeAttributes(io: out->addRect ("ImageRect", ImageRect); out->addTexture ("PressedImage", PressedImage); out->addRect ("PressedImageRect",PressedImageRect); + out->addTexture ("DisabledImage", DisabledImage); + out->addRect ("DisabledImageRect",DisabledImageRect); out->addBool ("Border", Border); out->addBool ("UseAlphaChannel", UseAlphaChannel); + out->addBool ("IsFlashing", IsFlashing); + out->addBool ("EnabledOverrideTextColor", EnabledOverrideTextColor); + out->addColor ("OverrideTextColor", OverrideTextColor); + + if ( OverrideFont && OverrideFont->getName().size() ) + out->addString("OverrideFont", OverrideFont->getName().c_str() ); - // out->addString ("OverrideFont", OverrideFont); } //! Reads attributes of the element @@ -451,10 +600,23 @@ void CGUIButton::deserializeAttributes(i else setPressedImage( in->getAttributeAsTexture("PressedImage") ); + rec = in->getAttributeAsRect("DisabledImageRect"); + if (rec.isValid()) + setDisabledImage( in->getAttributeAsTexture("DisabledImage"), rec); + else + setDisabledImage( in->getAttributeAsTexture("DisabledImage") ); + setDrawBorder(in->getAttributeAsBool("Border")); UseAlphaChannel = in->getAttributeAsBool("UseAlphaChannel"); + setFlashing(in->getAttributeAsBool("IsFlashing")); + EnabledOverrideTextColor = in->getAttributeAsBool("EnabledOverrideTextColor"); + OverrideTextColor = in->getAttributeAsColor("OverrideTextColor"); - // setOverrideFont(in->getAttributeAsString("OverrideFont")); + core::stringc fontName = in->getAttributeAsString("OverrideFont"); + if ( fontName.size() ) + { + setOverrideFont( Environment->getFont(fontName.c_str()) ); + } updateAbsolutePosition(); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIButton.h Irrlicht_starsonata/source/Irrlicht/CGUIButton.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIButton.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIButton.h 2008-03-20 04:50:26.000000000 +0100 @@ -34,6 +34,10 @@ namespace gui //! sets another skin independent font. if this is set to zero, the button uses the font of the skin. virtual void setOverrideFont(IGUIFont* font=0); + // Starsonata, Micha + //! Return the font which is used for this button + virtual IGUIFont* getCurrentFont(); + //! Sets an image which should be displayed on the button when it is in normal state. virtual void setImage(video::ITexture* image); @@ -46,6 +50,15 @@ namespace gui //! Sets an image which should be displayed on the button when it is in pressed state. virtual void setPressedImage(video::ITexture* image, const core::rect& pos); + //! Sets the background image which should be displayed on the button when it is in disabled state. + /** \param image: Image to be displayed */ + virtual void setDisabledImage(video::ITexture* image); + + //! Sets the background image which should be displayed on the button when it is in disabled state. + /** \param image: Texture containing the image to be displayed + \param pos: Position in the texture, where the image is located */ + virtual void setDisabledImage(video::ITexture* image, const core::rect& pos); + //! Sets the sprite bank used by the button virtual void setSpriteBank(IGUISpriteBank* bank); @@ -67,6 +80,7 @@ namespace gui virtual bool isPressed(); //! Sets the pressed state of the button if this is a pushbutton + //! This will not cause EGET_PUSHBUTTON_STATE_CHANGED events virtual void setPressed(bool pressed); //! Sets if the button should use the skin to draw its border @@ -84,6 +98,31 @@ namespace gui //! Returns whether the button is a push button virtual bool isPushButton(); + // starsonata, micha: flashing background + //! enabled/disable flashing of the button background + virtual void setFlashing(bool flash_); + + // starsonata, micha: flashing background + //! is the button background flashing + virtual bool isFlashing() const; + + // starsonata, micha: flashing background + //! get the state of the shift key when the last click event was created + virtual bool getClickShiftState() const { return ClickShiftState; } + + // starsonata, micha: flashing background + //! get the state of the control key when the last click event was created + virtual bool getClickControlState() const { return ClickControlState; } + + // starsonata, micha: override the usual text color + //! set a new textcolor which can override the default from the skin + //! the override color will only be used if enableOverrideColor is set to true + virtual void setOverrideTextColor( video::SColor color=video::SColor(255,255,255,255) ); + + // starsonata, micha: override the usual text color + //! use the color from setOverrideTextColor instead of the skin color + virtual void enableOverrideTextColor(bool enable); + //! Writes attributes of the element. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); @@ -102,23 +141,30 @@ namespace gui bool Pressed; bool IsPushButton; bool UseAlphaChannel; + bool IsFlashing; bool Border; - u32 MouseOverTime; - u32 FocusTime; u32 ClickTime; + bool ClickShiftState; + bool ClickControlState; + IGUISpriteBank* SpriteBank; IGUIFont* OverrideFont; + bool EnabledOverrideTextColor; + video::SColor OverrideTextColor; + ButtonSprite ButtonSprites[EGBS_COUNT]; video::ITexture* Image; video::ITexture* PressedImage; + video::ITexture* DisabledImage; core::rect ImageRect; core::rect PressedImageRect; + core::rect DisabledImageRect; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUICheckBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUICheckBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUICheckBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUICheckBox.cpp 2008-05-29 03:31:18.000000000 +0200 @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CGUICheckBox.h" +#include "IGUISpriteBank.h" #include "IGUISkin.h" #include "IGUIEnvironment.h" #include "IVideoDriver.h" @@ -16,7 +17,10 @@ namespace gui //! constructor CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) -: IGUICheckBox(environment, parent, id, rectangle), Pressed(false), Checked(checked), checkTime(0) +: IGUICheckBox(environment, parent, id, rectangle), Pressed(false), Checked(checked), CheckTime(0) +, IconChecked(-1) +, IconUnchecked(-1) +, IconBank(NULL) { #ifdef _DEBUG setDebugName("CGUICheckBox"); @@ -32,6 +36,8 @@ CGUICheckBox::CGUICheckBox(bool checked, //! destructor CGUICheckBox::~CGUICheckBox() { + if (IconBank) + IconBank->drop(); } @@ -39,6 +45,9 @@ CGUICheckBox::~CGUICheckBox() //! called if an event happened. bool CGUICheckBox::OnEvent(SEvent event) { + if ( !IsEnabled ) + return IGUIElement::OnEvent(event); + switch(event.EventType) { case EET_KEY_INPUT_EVENT: @@ -85,7 +94,7 @@ bool CGUICheckBox::OnEvent(SEvent event) if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { Pressed = true; - checkTime = os::Timer::getTime(); + CheckTime = os::Timer::getTime(); Environment->setFocus(this); return true; } @@ -118,7 +127,7 @@ bool CGUICheckBox::OnEvent(SEvent event) break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } @@ -130,6 +139,7 @@ void CGUICheckBox::draw() return; IGUISkin* skin = Environment->getSkin(); + IGUISpriteBank* currentIconBank = IconBank ? IconBank : skin->getSpriteBank(); core::rect rect = AbsoluteRect; @@ -142,12 +152,31 @@ void CGUICheckBox::draw() checkRect.LowerRightCorner.X = checkRect.UpperLeftCorner.X + height; checkRect.LowerRightCorner.Y = checkRect.UpperLeftCorner.Y + height; + bool customDrawing = false; + if ( Checked && IconChecked >= 0 ) + { + customDrawing = true; + currentIconBank->draw2DSprite( (u32)IconChecked, checkRect.getCenter(), &AbsoluteClippingRect, + Pressed || !IsEnabled ? skin->getColor(EGDC_ICON_HIGH_LIGHT) : skin->getColor(EGDC_ICON), + CheckTime, os::Timer::getTime(), false, true); + } + else if ( !Checked && IconUnchecked >= 0 ) + { + customDrawing = true; + currentIconBank->draw2DSprite( (u32)IconUnchecked, checkRect.getCenter(), &AbsoluteClippingRect, + Pressed || !IsEnabled ? skin->getColor(EGDC_ICON_HIGH_LIGHT) : skin->getColor(EGDC_ICON), + CheckTime, os::Timer::getTime(), false, true); + } + + if ( ! customDrawing ) + { skin->draw3DSunkenPane(this, skin->getColor(Pressed ? EGDC_3D_FACE : EGDC_ACTIVE_CAPTION), false, true, checkRect, &AbsoluteClippingRect); if (Checked && Environment->getSkin()) Environment->getSkin()->drawIcon(this, EGDI_CHECK_BOX_CHECKED, checkRect.getCenter(), - checkTime, os::Timer::getTime(), false, &AbsoluteClippingRect); + CheckTime, os::Timer::getTime(), false, &AbsoluteClippingRect); + } if (Text.size()) { @@ -157,7 +186,7 @@ void CGUICheckBox::draw() IGUIFont* font = skin->getFont(); if (font) font->draw(Text.c_str(), checkRect, - skin->getColor(EGDC_BUTTON_TEXT), false, true, &AbsoluteClippingRect); + skin->getColor( !IsEnabled ? EGDC_GRAY_TEXT : EGDC_BUTTON_TEXT), false, true, &AbsoluteClippingRect); } IGUIElement::draw(); @@ -178,17 +207,56 @@ bool CGUICheckBox::isChecked() return Checked; } +void CGUICheckBox::setSpriteBank(const c8 *bankName) +{ + IconBankName = core::stringc(bankName); + IGUISpriteBank* bank = IconBankName.size() ? Environment->getSpriteBank(IconBankName.c_str()) : NULL; + if ( bank != IconBank ) + { + if (IconBank) + IconBank->drop(); + IconBank = bank; + if (IconBank) + IconBank->grab(); + } +} + +void CGUICheckBox::setIconChecked(s32 spriteIdx) +{ + IconChecked = spriteIdx; +} + +void CGUICheckBox::setIconUnChecked(s32 spriteIdx) +{ + IconUnchecked = spriteIdx; +} + //! Writes attributes of the element. void CGUICheckBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) { IGUICheckBox::serializeAttributes(out,options); out->addBool ("Checked", Checked ); + out->addInt ("IconChecked", IconChecked ); + out->addInt ("IconUnchecked", IconUnchecked ); + out->addString ("IconBankName", IconBankName.c_str() ); } //! Reads attributes of the element void CGUICheckBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { + Pressed = false; Checked = in->getAttributeAsBool ("Checked"); + CheckTime = 0; + IconChecked = in->getAttributeAsInt("IconChecked"); + IconUnchecked = in->getAttributeAsInt("IconUnchecked"); + + IconBankName = in->getAttributeAsString("IconBankName"); + setSpriteBank(IconBankName.c_str()); + + if ( IconBankName.size() && !IconBank ) + { + os::Printer::log("CGUICheckBox::deserializeAttributes Got no sprite bank for", IconBankName.c_str(), ELL_ERROR); + } IGUICheckBox::deserializeAttributes(in,options); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUICheckBox.h Irrlicht_starsonata/source/Irrlicht/CGUICheckBox.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUICheckBox.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUICheckBox.h 2008-04-25 22:48:38.000000000 +0200 @@ -11,6 +11,7 @@ namespace irr { namespace gui { + class IGUISpriteBank; class CGUICheckBox : public IGUICheckBox { @@ -28,6 +29,20 @@ namespace gui //! returns if box is checked virtual bool isChecked(); + // starsonata, micha - adding spritesupport to have more layout possibilities + //! Set the spritebank which will be used to draw custom icons. + virtual void setSpriteBank(const c8 *bankName); + + // starsonata, micha + //! Set a sprite which will be used for drawing in "checked" state + //! Set the spritebank for this in setSpriteBank, otherwise the spritebank of the default skin is used + virtual void setIconChecked(s32 spriteIdx); + + // starsonata, micha + //! set a sprite which will be used for drawing in "unchecked" state + //! Set the spritebank for this in setSpriteBank, otherwise the spritebank of the default skin is used + virtual void setIconUnChecked(s32 spriteIdx); + //! called if an event happened. virtual bool OnEvent(SEvent event); @@ -44,7 +59,11 @@ namespace gui bool Pressed; bool Checked; - u32 checkTime; + u32 CheckTime; + s32 IconChecked; + s32 IconUnchecked; + core::stringc IconBankName; + IGUISpriteBank* IconBank; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIColorSelectDialog.cpp Irrlicht_starsonata/source/Irrlicht/CGUIColorSelectDialog.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIColorSelectDialog.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIColorSelectDialog.cpp 2008-05-23 00:58:20.000000000 +0200 @@ -136,7 +136,7 @@ CGUIColorSelectDialog::CGUIColorSelectDi r.LowerRightCorner.X = r.UpperLeftCorner.X + 35; r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; - item.Edit = Environment->addEditBox( Template[i].init, r, true, this); + item.Edit = Environment->addEditBox( Template[i].init, r, true, false, this); item.Edit->setSubElement(true); item.Edit->grab(); @@ -338,6 +338,8 @@ void CGUIColorSelectDialog::buildColorRi //! called if an event happened. bool CGUIColorSelectDialog::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); switch(event.EventType) { diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIComboBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUIComboBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIComboBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIComboBox.cpp 2008-06-13 19:45:42.000000000 +0200 @@ -44,8 +44,8 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironme if (skin && skin->getSpriteBank()) { ListButton->setSpriteBank(skin->getSpriteBank()); - ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL)); - ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL)); + ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_DROP_DOWN), skin->getColor(EGDC_ICON)); + ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_DROP_DOWN_PRESSED), skin->getColor(EGDC_ICON)); } ListButton->setSubElement(true); ListButton->setTabStop(false); @@ -77,7 +77,7 @@ const wchar_t* CGUIComboBox::getItem(s32 if (idx < 0 || idx >= (s32)Items.size()) return 0; - return Items[idx].c_str(); + return Items[idx].Text.c_str(); } //! Removes an item from the combo box. @@ -102,7 +102,7 @@ const wchar_t* CGUIComboBox::getText() //! adds an item and returns the index of it s32 CGUIComboBox::addItem(const wchar_t* text) { - Items.push_back(core::stringw(text)); + Items.push_back( Item(core::stringw(text)) ); if (Selected == -1) Selected = 0; @@ -144,6 +144,7 @@ void CGUIComboBox::updateAbsolutePositio s32 width = Environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH); + if ( ListButton ) ListButton->setRelativePosition(core::rect(RelativeRect.getWidth() - width - 2, 2, RelativeRect.getWidth() - 2, RelativeRect.getHeight() - 2)); } @@ -152,6 +153,9 @@ void CGUIComboBox::updateAbsolutePositio //! called if an event happened. bool CGUIComboBox::OnEvent(SEvent event) { + if ( !IsEnabled ) + return IGUIElement::OnEvent(event); + switch(event.EventType) { @@ -300,7 +304,7 @@ bool CGUIComboBox::OnEvent(SEvent event) break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } @@ -356,10 +360,12 @@ void CGUIComboBox::draw() IGUIFont* font = skin->getFont(); if (font) - font->draw(Items[Selected].c_str(), frameRect, - skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT), + { + font->draw(Items[Selected].Text.c_str(), frameRect, + skin->getColor(!IsEnabled ? EGDC_GRAY_TEXT : (HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT)), false, true, &AbsoluteClippingRect); } + } // draw buttons IGUIElement::draw(); @@ -399,9 +405,11 @@ void CGUIComboBox::openCloseMenu() ListBox = new CGUIListBox(Environment, this, -1, r, false, true, true); ListBox->setSubElement(true); ListBox->drop(); + video::SColor bkcolor = skin->getColor(EGDC_3D_FACE); + ListBox->setBackgroundOverrideColor( bkcolor ); for (s32 i=0; i<(s32)Items.size(); ++i) - ListBox->addItem(Items[i].c_str()); + ListBox->addItem(Items[i].Text.c_str()); ListBox->setSelected(Selected); @@ -410,22 +418,52 @@ void CGUIComboBox::openCloseMenu() } } + //! Writes attributes of the element. void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) { IGUIComboBox::serializeAttributes(out,options); out->addInt ("Selected", Selected ); - out->addArray ("Items", Items); + + // done that way as it keeps downward compatibility + core::array< core::stringw > ItemTexts; + for ( u32 i=0; i < Items.size(); ++i ) + ItemTexts.push_back( Items[i].Text ); + out->addArray ("Items", ItemTexts); } //! Reads attributes of the element void CGUIComboBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { - Items = in->getAttributeAsArray("Items"); IGUIComboBox::deserializeAttributes(in,options); setSelected(in->getAttributeAsInt("Selected")); + + Items.clear(); + core::array< core::stringw > ItemTexts; + ItemTexts = in->getAttributeAsArray("Items"); + for ( u32 i=0; i < ItemTexts.size(); ++i ) + Items.push_back( Item(ItemTexts[i]) ); +} + + +//! set the custom data field for the item +void CGUIComboBox::setItemData(s32 idx, void *data) +{ + if (idx < 0 || idx >= (s32)Items.size()) + return; + + Items[idx].UserData = data; +} + +//! get the custom data field for the item +void* CGUIComboBox::getItemData(s32 idx) const +{ + if (idx < 0 || idx >= (s32)Items.size()) + return 0; + + return Items[idx].UserData; } } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIComboBox.h Irrlicht_starsonata/source/Irrlicht/CGUIComboBox.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIComboBox.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIComboBox.h 2007-12-28 05:57:50.000000000 +0100 @@ -64,6 +64,12 @@ namespace gui //! Reads attributes of the element virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); + //! set the custom data field for the item + virtual void setItemData(s32 idx, void *data); + + //! get the custom data field for the item + virtual void* getItemData(s32 idx) const; + private: void openCloseMenu(); @@ -71,10 +77,19 @@ namespace gui IGUIButton* ListButton; IGUIListBox* ListBox; - core::array< core::stringw > Items; s32 Selected; bool HasFocus; IGUIElement *LastFocus; + + struct Item + { + Item() : UserData(0) {} + Item(const core::stringw& text) : Text(text), UserData(0) {} + + core::stringw Text; + void * UserData; + }; + core::array< Item > Items; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIContextMenu.cpp Irrlicht_starsonata/source/Irrlicht/CGUIContextMenu.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIContextMenu.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIContextMenu.cpp 2008-06-06 07:40:36.000000000 +0200 @@ -22,7 +22,7 @@ CGUIContextMenu::CGUIContextMenu(IGUIEnv IGUIElement* parent, s32 id, core::rect rectangle, bool getFocus, bool allowFocus) : IGUIContextMenu(environment, parent, id, rectangle), HighLighted(-1), - ChangeTime(0), EventParent(0), AllowFocus(allowFocus) + ChangeTime(0), EventParent(0), AllowFocus(allowFocus), CloseHandling(ECMC_REMOVE) { #ifdef _DEBUG setDebugName("CGUIContextMenu"); @@ -55,11 +55,12 @@ s32 CGUIContextMenu::getItemCount() cons //! Adds a menu item. -s32 CGUIContextMenu::addItem(const wchar_t* text, s32 id, bool enabled, bool hasSubMenu, bool checked) +s32 CGUIContextMenu::addItem(const wchar_t* text, s32 id, bool enabled, bool hasSubMenu, bool checked, bool autoChecking) { SItem s; s.Enabled = enabled; s.Checked = checked; + s.AutoChecking = autoChecking; s.Text = text; s.IsSeparator = (text == 0); s.SubMenu = 0; @@ -78,6 +79,18 @@ s32 CGUIContextMenu::addItem(const wchar return Items.size() - 1; } +s32 CGUIContextMenu::findItemWithCommandId(s32 commandId, u32 idxStartSearch) +{ + for ( u32 i=idxStartSearch; isetVisible(false); if (Items[index].SubMenu) + { menu->grab(); + menu->AllowFocus = false; + if ( Environment->getFocus() == menu ) + { + Environment->setFocus( this ); + } + } recalculateSize(); } @@ -100,7 +120,7 @@ void CGUIContextMenu::setSubMenu(s32 ind //! Adds a separator item to the menu void CGUIContextMenu::addSeparator() { - addItem(0, -1, true, false, false); + addItem(0, -1, true, false, false, false); } @@ -125,6 +145,41 @@ void CGUIContextMenu::setItemText(s32 id } +void CGUIContextMenu::setItemAutoChecking(s32 idx, bool autoChecking) +{ + if (idx < 0 || idx >= (s32)Items.size()) + return; + + Items[idx].AutoChecking = autoChecking; +} + +bool CGUIContextMenu::getItemAutoChecking(s32 idx) +{ + if (idx < 0 || idx >= (s32)Items.size()) + return false; + + return Items[idx].AutoChecking; +} + +//! Starsonata, MICHA: textID for stringtables +const wchar_t* CGUIContextMenu::getItemTextID(s32 idx) +{ + if (idx < 0 || idx >= (s32)Items.size()) + return 0; + + return Items[idx].TextID.c_str(); +} + +//! Starsonata, MICHA: textID for stringtables +void CGUIContextMenu::setItemTextID(s32 idx, const wchar_t* text) +{ + if (idx < 0 || idx >= (s32)Items.size()) + return; + + Items[idx].TextID = text; +} + + //! Returns if a menu item is enabled bool CGUIContextMenu::isItemEnabled(s32 idx) { @@ -199,12 +254,23 @@ void CGUIContextMenu::removeAllItems() recalculateSize(); } +void CGUIContextMenu::popupAt(irr::s32 x_, irr::s32 y_) +{ + core::position2d p(x_, y_); + move( p - getAbsolutePosition().UpperLeftCorner ); + setVisible(true); + bringToTop(); + Environment->setFocus(this); + IGUIElement * root = Environment->getRootGUIElement(); + if ( root ) + moveInside( root->getAbsolutePosition(), EGUIA_UPPERLEFT); +} //! called if an event happened. bool CGUIContextMenu::OnEvent(SEvent event) { - if (!IsEnabled) - return Parent ? Parent->OnEvent(event) : false; + if (!IsEnabled || !isVisible() ) + return IGUIElement::OnEvent(event); switch(event.EventType) { @@ -212,11 +278,23 @@ bool CGUIContextMenu::OnEvent(SEvent eve switch(event.GUIEvent.EventType) { case EGET_ELEMENT_FOCUS_LOST: - if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element)) + if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element) && AllowFocus) { // set event parent of submenus - setEventParent(Parent); + setEventParent(EventParent ? EventParent : Parent); + + if ( CloseHandling & ECMC_HIDE ) + { + setVisible(false); + } + if ( CloseHandling & ECMC_DROP ) + { + drop(); + } + if ( CloseHandling & ECMC_REMOVE ) + { remove(); + } return false; } break; @@ -225,6 +303,9 @@ bool CGUIContextMenu::OnEvent(SEvent eve { return true; } + break; + default: + break; } break; case EET_MOUSE_INPUT_EVENT: @@ -241,16 +322,17 @@ bool CGUIContextMenu::OnEvent(SEvent eve } return true; case EMIE_LMOUSE_PRESSED_DOWN: + // to prevent losing focus return true; case EMIE_MOUSE_MOVED: if (Environment->hasFocus(this)) - highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y)); - return true; + highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), true); + return false; } break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } @@ -302,16 +384,20 @@ s32 CGUIContextMenu::sendClick(core::pos Items[HighLighted].SubMenu) return 2; + if ( Items[HighLighted].AutoChecking ) + { + Items[HighLighted].Checked = Items[HighLighted].Checked ? false : true; + } + SEvent event; event.EventType = EET_GUI_EVENT; event.GUIEvent.Caller = this; event.GUIEvent.Element = 0; event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED; - if (Parent) - Parent->OnEvent(event); - else if (EventParent) EventParent->OnEvent(event); + else if (Parent) + Parent->OnEvent(event); return 1; } @@ -321,7 +407,7 @@ s32 CGUIContextMenu::sendClick(core::pos //! returns true, if an element was highligted -bool CGUIContextMenu::highlight(core::position2d p) +bool CGUIContextMenu::highlight(core::position2d p, bool canOpenSubMenu) { // get number of open submenu s32 openmenu = -1; @@ -336,7 +422,7 @@ bool CGUIContextMenu::highlight(core::po // delegate highlight operation to submenu if (openmenu != -1) { - if (Items[openmenu].SubMenu->highlight(p)) + if (Items[openmenu].SubMenu->highlight(p, canOpenSubMenu)) { HighLighted = openmenu; ChangeTime = os::Timer::getTime(); @@ -354,7 +440,12 @@ bool CGUIContextMenu::highlight(core::po // make submenus visible/invisible for (s32 j=0; j<(s32)Items.size(); ++j) if (Items[j].SubMenu) - Items[j].SubMenu->setVisible(j == i); + { + if ( j == i && canOpenSubMenu ) + Items[j].SubMenu->setVisible(true); + else if ( j != i ) + Items[j].SubMenu->setVisible(false); + } return true; } @@ -474,7 +565,8 @@ void CGUIContextMenu::draw() if (Items[i].Checked && sprites) { core::rect r = rect; - r.UpperLeftCorner.X -= 15; + r.LowerRightCorner.X = r.UpperLeftCorner.X - 15; + r.UpperLeftCorner.X = r.LowerRightCorner.X + 15; sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED), r.getCenter(), clip, skin->getColor(c), (i == HighLighted) ? ChangeTime : 0, @@ -599,6 +691,8 @@ void CGUIContextMenu::serializeAttribute out->addInt("ParentItem", i); } + out->addInt("CloseHandling", (s32)CloseHandling); + // write out the item list out->addInt("ItemCount", Items.size()); @@ -614,10 +708,23 @@ void CGUIContextMenu::serializeAttribute { tmp = "Text"; tmp += i; out->addString(tmp.c_str(), Items[i].Text.c_str()); + + // Starsonata, MICHA: textID for stringtables + tmp = "TextID"; tmp += i; + out->addString(tmp.c_str(), Items[i].TextID.c_str()); + tmp = "CommandID"; tmp += i; out->addInt(tmp.c_str(), Items[i].CommandId); tmp = "Enabled"; tmp += i; out->addBool(tmp.c_str(), Items[i].Enabled); + + // Starsonata, MICHA: was not serialized + tmp = "Checked"; tmp += i; + out->addBool(tmp.c_str(), Items[i].Checked); + + // Starsonata, MICHA: menus can set the checkflag themself + tmp = "AutoChecking"; tmp += i; + out->addBool(tmp.c_str(), Items[i].AutoChecking); } } } @@ -639,36 +746,58 @@ void CGUIContextMenu::deserializeAttribu // read the item list s32 count = in->getAttributeAsInt("ItemCount"); + // starsonata, micha: + // Added some existsAttribute checks to allow for incomplete xml's as the usual default mechanism + // does not work for sub-elements. So defaults are hardcoded, but still better than having to type them + // so often in the xml's. + s32 i=0; for (; i<(s32)count; ++i) { core::stringc tmp; core::stringw txt; - s32 commandid; - bool enabled; - bool checked; + core::stringw txtID; + s32 commandid=-1; + bool enabled=true; + bool checked=false; + bool autochecking=false; tmp = "IsSeparator"; tmp += i; - if ( in->getAttributeAsBool(tmp.c_str()) ) + if ( in->existsAttribute(tmp.c_str()) && in->getAttributeAsBool(tmp.c_str()) ) addSeparator(); else { tmp = "Text"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) txt = in->getAttributeAsStringW(tmp.c_str()); + // Starsonata, MICHA: textID for stringtables + tmp = "TextID"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + txtID = in->getAttributeAsStringW(tmp.c_str()); + tmp = "CommandID"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) commandid = in->getAttributeAsInt(tmp.c_str()); tmp = "Enabled"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) enabled = in->getAttributeAsBool(tmp.c_str()); tmp = "Checked"; tmp += i; checked = in->getAttributeAsBool(tmp.c_str()); - addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked); + // Starsonata, MICHA: menus can set the checkflag themself + tmp = "AutoChecking"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + autochecking = in->getAttributeAsBool(tmp.c_str()); + + s32 id = addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked, autochecking); + Items[id].TextID = txtID; } } + CloseHandling = (ECONTEXT_MENU_CLOSE)in->getAttributeAsInt("CloseHandling"); recalculateSize(); @@ -686,6 +815,35 @@ void CGUIContextMenu::setEventParent(IGU } } +bool CGUIContextMenu::hasOpenSubMenu() +{ + for (s32 i=0; i<(s32)Items.size(); ++i) + if (Items[i].SubMenu) + if ( Items[i].SubMenu->isVisible() ) + return true; + return false; +} + +void CGUIContextMenu::closeAllSubMenus() +{ + for (s32 i=0; i<(s32)Items.size(); ++i) + if (Items[i].SubMenu) + Items[i].SubMenu->setVisible(false); + + //HighLighted = -1; +} + +void CGUIContextMenu::setCloseHandling(ECONTEXT_MENU_CLOSE onClose) +{ + CloseHandling = onClose; +} + +ECONTEXT_MENU_CLOSE CGUIContextMenu::getCloseHandling() const +{ + return CloseHandling; +} + + } // end namespace } // end namespace diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIContextMenu.h Irrlicht_starsonata/source/Irrlicht/CGUIContextMenu.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIContextMenu.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIContextMenu.h 2008-06-06 07:41:28.000000000 +0200 @@ -33,7 +33,7 @@ namespace gui //! Adds a menu item. virtual s32 addItem(const wchar_t* text, s32 commandid, bool enabled, bool hasSubMenu, - bool checked); + bool checked, bool autoChecking); //! Adds a separator item to the menu virtual void addSeparator(); @@ -44,6 +44,10 @@ namespace gui //! Sets text of the menu item. virtual void setItemText(s32 idx, const wchar_t* text); + //! Starsonata, MICHA: textID for stringtables + virtual const wchar_t* getItemTextID(s32 idx); + virtual void setItemTextID(s32 idx, const wchar_t* text); + //! Returns if a menu item is enabled virtual bool isItemEnabled(s32 idx); @@ -84,6 +88,11 @@ namespace gui //! Sets the command id of a menu item virtual void setItemCommandId(s32 idx, s32 id); + // starsonata, micha - a useful comfort function + //! Find a item which has the given CommandId starting from given index (or idxStartSearch=0 for searching from start) + //! return -1 if no such item was found + virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch); + //! Adds a sub menu from an element that already exists. virtual void setSubMenu(s32 index, CGUIContextMenu* menu); @@ -93,14 +102,38 @@ namespace gui //! Reads attributes of the element virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); + //! set behaviour when menus are closed + virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose); + + //! get current behaviour when the menue will be closed + virtual ECONTEXT_MENU_CLOSE getCloseHandling() const; + + //! should the element change the checked status on clicking + virtual void setItemAutoChecking(s32 idx, bool autoChecking); + + //! does the element change the checked status on clicking + virtual bool getItemAutoChecking(s32 idx); + + //! Make sure to show it at a good place around the given coordinates. + //! A comfort function which can for example be used after right-clicks with the mouse coordinates. + virtual void popupAt(irr::s32 x_, irr::s32 y_); + + // Starsonata, Micha, this was protected formerly, but it's rather useful as general functions for popups + virtual void setEventParent(IGUIElement *parent); + protected: + void closeAllSubMenus(); + bool hasOpenSubMenu(); + struct SItem { core::stringw Text; + core::stringw TextID; // Starsonata, MICHA: textID for stringtables bool IsSeparator; bool Enabled; bool Checked; + bool AutoChecking; core::dimension2d Dim; s32 PosY; CGUIContextMenu* SubMenu; @@ -109,8 +142,8 @@ namespace gui virtual void recalculateSize(); - //! returns true, if an element was highligted - virtual bool highlight(core::position2d p); + //! returns true, if an element was highlighted + virtual bool highlight(core::position2d p, bool canOpenSubMenu); //! sends a click Returns: //! 0 if click went outside of the element, @@ -124,14 +157,13 @@ namespace gui //! Gets drawing rect of Item virtual core::rect getRect(const SItem& i, const core::rect& absolute); - void setEventParent(IGUIElement *parent); - s32 HighLighted; core::array Items; core::position2d Pos; u32 ChangeTime; IGUIElement* EventParent; bool AllowFocus; + ECONTEXT_MENU_CLOSE CloseHandling; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEditBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUIEditBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEditBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIEditBox.cpp 2008-06-05 10:15:42.000000000 +0200 @@ -26,11 +26,11 @@ namespace gui { //! constructor -CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment, +CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, bool transparent, IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect& rectangle) : IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false), - Border(border), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0), + Border(border), Transparent(transparent), OverrideColorEnabled(false), IsPasswordField( false ), MarkBegin(0), MarkEnd(0), OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0), WordWrap(false), MultiLine(false), AutoScroll(true), @@ -53,6 +53,11 @@ CGUIEditBox::CGUIEditBox(const wchar_t* setTabOrder(-1); breakText(); + + if ( Text.size() ) + { + sendTextChangedEvent(); + } } @@ -70,6 +75,9 @@ CGUIEditBox::~CGUIEditBox() //! Sets another skin independent font. void CGUIEditBox::setOverrideFont(IGUIFont* font) { + if ( OverrideFont == font ) + return; + if (OverrideFont) OverrideFont->drop(); @@ -168,7 +176,7 @@ bool CGUIEditBox::OnEvent(SEvent event) break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } @@ -177,6 +185,9 @@ bool CGUIEditBox::processKey(const SEven if (!event.KeyInput.PressedDown) return false; + if ( !isVisible() ) + return false; + bool textChanged = false; // control shortcut handling @@ -606,7 +617,10 @@ bool CGUIEditBox::processKey(const SEven // break the text if it has changed if (textChanged) + { breakText(); + sendTextChangedEvent(); + } calculateScrollPos(); @@ -631,8 +645,12 @@ void CGUIEditBox::draw() if (Border) { - skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW), - false, true, frameRect, &AbsoluteClippingRect); + video::SColor color = Environment->hasFocus(this) ? + skin->getColor(EGDC_FOCUSED_EDITBOX) : + skin->getColor(EGDC_WINDOW); + + skin->draw3DSunkenPane(this, color, + false, Transparent, frameRect, &AbsoluteClippingRect); frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1; frameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; @@ -656,9 +674,16 @@ void CGUIEditBox::draw() if (LastBreakFont != font) breakText(); + core::stringw finalText(Text); + if ( IsPasswordField ) + { + for ( int i = 0 ; i < (int)finalText.size(); ++i ) + finalText[i] = L'*'; + } + // calculate cursor pos - core::stringw *txtLine = &Text; + core::stringw *txtLine = &finalText; s32 startPos = 0; core::stringw s, s2; @@ -675,7 +700,7 @@ void CGUIEditBox::draw() bool prevOver = OverrideColorEnabled; video::SColor prevColor = OverrideColor; - if (Text.size()) + if (finalText.size()) { if ( !this->IsEnabled && !OverrideColorEnabled ) { @@ -694,7 +719,7 @@ void CGUIEditBox::draw() continue; // get current line - txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text; + txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &finalText; startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0; // draw normal text @@ -781,6 +806,7 @@ void CGUIEditBox::setText(const wchar_t* MarkBegin = 0; MarkEnd = 0; breakText(); + sendTextChangedEvent(); } //! Enables or disables automatic scrolling with cursor position @@ -838,6 +864,12 @@ s32 CGUIEditBox::getMax() return Max; } +void CGUIEditBox::setCursorPosition( u32 pos ) +{ + if ( pos < Text.size() ) + CursorPos = pos; +} + bool CGUIEditBox::processMouse(const SEvent& event) { @@ -1187,8 +1219,9 @@ void CGUIEditBox::inputChar(wchar_t c) MarkBegin = 0; MarkEnd = 0; } - } breakText(); + sendTextChangedEvent(); + } } @@ -1249,13 +1282,17 @@ void CGUIEditBox::serializeAttributes(io out->addBool ("OverrideColorEnabled", OverrideColorEnabled ); out->addColor ("OverrideColor", OverrideColor); - // out->addFont("OverrideFont",OverrideFont); out->addInt ("MaxChars", Max); out->addBool ("WordWrap", WordWrap); out->addBool ("MultiLine", MultiLine); out->addBool ("AutoScroll", AutoScroll); out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); + out->addBool ("IsPasswordField", IsPasswordField); + + + if ( OverrideFont && OverrideFont->getName().size() ) + out->addString("OverrideFont", OverrideFont->getName().c_str() ); IGUIEditBox::serializeAttributes(out,options); } @@ -1271,13 +1308,32 @@ void CGUIEditBox::deserializeAttributes( setWordWrap(in->getAttributeAsBool("WordWrap")); setMultiLine(in->getAttributeAsBool("MultiLine")); setAutoScroll(in->getAttributeAsBool("AutoScroll")); + setPasswordField(in->getAttributeAsBool("IsPasswordField")); setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames), (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); - // setOverrideFont(in->getAttributeAsFont("OverrideFont")); + core::stringc fontName = in->getAttributeAsString("OverrideFont"); + if ( fontName.size() ) + { + setOverrideFont( Environment->getFont(fontName.c_str()) ); + } +} + +void CGUIEditBox::setPasswordField( bool isPasswordField ) +{ + this->IsPasswordField = isPasswordField; } +void CGUIEditBox::sendTextChangedEvent() +{ + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_EDITBOX_TEXT_CHANGED; + Parent->OnEvent(e); +} } // end namespace gui } // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEditBox.h Irrlicht_starsonata/source/Irrlicht/CGUIEditBox.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEditBox.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIEditBox.h 2008-02-23 00:56:58.000000000 +0100 @@ -18,7 +18,7 @@ namespace gui public: //! constructor - CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment, + CGUIEditBox(const wchar_t* text, bool border, bool transparent, IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect& rectangle); //! destructor @@ -85,6 +85,10 @@ namespace gui //! Returns maximum amount of characters, previously set by setMax(); virtual s32 getMax(); + virtual void setPasswordField( bool isPasswordField ); + + virtual void setCursorPosition( u32 pos ); + //! Updates the absolute position, splits text if required virtual void updateAbsolutePosition(); @@ -110,9 +114,14 @@ namespace gui bool processMouse(const SEvent& event); s32 getCursorPos(s32 x, s32 y); + // Starsonata, Micha: So far the only way to find out about that was polling. + void sendTextChangedEvent(); + bool MouseMarking; bool Border; + bool Transparent; bool OverrideColorEnabled; + bool IsPasswordField; s32 MarkBegin; s32 MarkEnd; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEnvironment.cpp Irrlicht_starsonata/source/Irrlicht/CGUIEnvironment.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEnvironment.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIEnvironment.cpp 2008-06-03 08:16:58.000000000 +0200 @@ -29,14 +29,19 @@ #include "CGUIComboBox.h" #include "CGUIMenu.h" #include "CGUIToolBar.h" +#include "CGUITable.h" +#include "Extended_CGUIRectangle.h" #include "CDefaultGUIElementFactory.h" #include "IWriteFile.h" #include "IXMLWriter.h" +#include "CAttributes.h" #include "BuiltInFont.h" #include "os.h" +#include "IGUIFontFactory.h" + namespace irr { namespace gui @@ -49,6 +54,7 @@ const wchar_t* IRR_XML_FORMAT_GUI_ELEMEN //! constructor CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op) : IGUIElement(EGUIET_ELEMENT, 0, 0, 0, core::rect(core::position2d(0,0), driver ? driver->getScreenSize() : core::dimension2d(0,0))), + DefaultElementAttributeUsage(io::EDAU_IGNORE), Driver(driver), Hovered(0), Focus(0), LastHoveredMousePos(0,0), CurrentSkin(0), FileSystem(fs), UserReceiver(0), Operator(op) { @@ -90,6 +96,12 @@ CGUIEnvironment::CGUIEnvironment(io::IFi //! destructor CGUIEnvironment::~CGUIEnvironment() { + for ( u32 i=0; i < Banks.size(); ++i ) + { + if ( Banks[i].Bank ) + Banks[i].Bank->drop(); + } + if (Hovered && Hovered != this) { Hovered->drop(); @@ -142,7 +154,10 @@ CGUIEnvironment::~CGUIEnvironment() // remove all factories for (i=0; idrop(); + for (i=0; idrop(); + clearDefaultElementAttributes(); } @@ -362,10 +377,13 @@ void CGUIEnvironment::clear() //! called by ui if an event happened. bool CGUIEnvironment::OnEvent(SEvent event) { - if (UserReceiver && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this)) + if (UserReceiver + && (event.EventType != EET_MOUSE_INPUT_EVENT) + && (event.EventType != EET_KEY_INPUT_EVENT) + && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this)) return UserReceiver->OnEvent(event); - return false; + return IGUIElement::OnEvent(event); } /* @@ -399,7 +417,7 @@ void CGUIEnvironment::OnPostRender( u32 ToolTip.Element = addStaticText(Hovered->getToolTipText().c_str(), pos, true, true, this, -1, true); ToolTip.Element->setOverrideColor(getSkin()->getColor(EGDC_TOOLTIP)); - ToolTip.Element->setBackgroundColor(getSkin()->getColor(EGDC_TOOLTIP_BACKGROUND)); + ToolTip.Element->setBackgroundOverrideColor(getSkin()->getColor(EGDC_TOOLTIP_BACKGROUND)); ToolTip.Element->setOverrideFont(getSkin()->getFont(EGDF_TOOLTIP)); ToolTip.Element->setSubElement(true); ToolTip.Element->grab(); @@ -500,6 +518,15 @@ bool CGUIEnvironment::postEventFromUser( setFocus(Hovered); } + // Starsonata, MICHA. We need to give the hovered window the chance to react on the mouse + // even when it's not focused. + // The "&& Focus" check is just because the event would be called a second time below otherwise + if ( Hovered && Focus && Hovered != Focus && event.MouseInput.Event == EMIE_MOUSE_MOVED ) + { + if ( Hovered->OnEvent(event) ) + return true; + } + // sending input to focus if (Focus && Focus->OnEvent(event)) return true; @@ -611,6 +638,16 @@ IGUIElementFactory* CGUIEnvironment::get return 0; } +//! get the typenumber for the elementname +EGUI_ELEMENT_TYPE CGUIEnvironment::getTypeFromName(const c8* name) +{ + EGUI_ELEMENT_TYPE type = EGUIET_ELEMENT; + for (s32 i=0; i<(int)GUIElementFactoryList.size() && type == EGUIET_ELEMENT; ++i) + type = GUIElementFactoryList[i]->getTypeFromName(name); + + return type; +} + //! adds a GUI Element using its name IGUIElement* CGUIEnvironment::addGUIElement(const c8* elementName, IGUIElement* parent) { @@ -625,6 +662,31 @@ IGUIElement* CGUIEnvironment::addGUIElem return node; } +//! Adds a font factory to the gui environment. +void CGUIEnvironment::registerGUIFontFactory(IGUIFontFactory* factoryToAdd) +{ + if (factoryToAdd) + { + factoryToAdd->grab(); + GUIFontFactoryList.push_back(factoryToAdd); + } +} + +//! Returns amount of registered font factories. +s32 CGUIEnvironment::getRegisteredGUIFontFactoryCount() +{ + return GUIFontFactoryList.size(); +} + +//! Returns a font factory by index +IGUIFontFactory* CGUIEnvironment::getGUIFontFactory(s32 index) +{ + if (index>=0 && index<(int)GUIFontFactoryList.size()) + return GUIFontFactoryList[index]; + + return 0; +} + //! Saves the current gui into a file. //! \param filename: Name of the file . @@ -706,7 +768,215 @@ bool CGUIEnvironment::loadGUI(io::IReadF } +void CGUIEnvironment::clearDefaultElementAttributes() +{ + for ( u32 i=0; i < DefaultElementAttributes.size(); ++i ) + { + DefaultElementAttributes[i].Attribute->drop(); + } + DefaultElementAttributes.clear(); +} + +bool CGUIEnvironment::loadDefaultElementAttributes(const c8* filename) +{ + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + if (!file) + { + os::Printer::log("Unable to open gui file", filename, ELL_ERROR); + return false; + } + + io::IXMLReader* reader = FileSystem->createXMLReader(file); + if (!reader) + { + file->drop(); + os::Printer::log("not a valid XML file", file->getFileName(), ELL_ERROR); + return false; + } + + // read file + while(reader->read()) + { + readDefaultElementAttribute(reader); + } + + // finish up + reader->drop(); + file->drop(); + + return true; + +} + +//! Set how the default attributes for elements should be used +void CGUIEnvironment::setDefaultElementAttributeUsage(io::E_DEFAULT_ATTRIBUTE_USAGE usage) +{ + DefaultElementAttributeUsage = usage; +} + +// Set a default element attribute, overriding former attributes of the same type +// The used Attribute will be grab'ed within this function. +void CGUIEnvironment::setDefaultElementAttribute(const SDefaultElementAttribute& attribute) +{ + if ( attribute.Attribute ) + attribute.Attribute->grab(); + for ( u32 i=0; idrop(); + DefaultElementAttributes[i] = attribute; + return; + } + } + DefaultElementAttributes.push_back( attribute ); +} + +void CGUIEnvironment::readDefaultElementAttribute(io::IXMLReader* reader) +{ + if (!reader) + return; + + SDefaultElementAttribute defaultAttrib; + + if ( reader->getNodeType() == io::EXN_NONE + || reader->getNodeType() == io::EXN_UNKNOWN + || reader->getNodeType() == io::EXN_ELEMENT_END) + return; + + if (!wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + // defaultAttrib.Type = ; CGUIEnvironment seems to have no own EGUI_ELEMENT_TYPE + } + else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName())) + { + // find node type and create it + core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE); + defaultAttrib.Type = getTypeFromName(attrName.c_str()); + defaultAttrib.TypeName = attrName; + } + + // read attributes + + while(reader->read()) + { + bool endreached = false; + + switch (reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || + !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + endreached = true; + } + break; + case io::EXN_ELEMENT: + if (!wcscmp(L"attributes", reader->getNodeName())) + { + // read attributes + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader, true); + if ( defaultAttrib.Type != EGUIET_ELEMENT ) + { + defaultAttrib.Attribute = attr; + setDefaultElementAttribute(defaultAttrib); + } + attr->drop(); + } + else + if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || + !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + readDefaultElementAttribute(reader); + } + else + { + os::Printer::log("Found unknown element in irrlicht GUI file", + core::stringc(reader->getNodeName()).c_str()); + } + + break; + } + + if (endreached) + break; + } +} + +bool CGUIEnvironment::saveDefaultElementAttributes(const c8* filename) +{ + io::IWriteFile* file = FileSystem->createAndWriteFile(filename); + if (!file) + return false; + + io::IXMLWriter* writer = FileSystem->createXMLWriter(file); + if (!writer) + { + file->drop(); + return false; + } + + writer->writeXMLHeader(); + + // root element start (to get a valid xml-file) + core::stringw nameRoot("unknown"); + writer->writeElement( IRR_XML_FORMAT_GUI_ELEMENT, + false, IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE, + nameRoot.c_str() ); + writer->writeLineBreak(); + writer->writeLineBreak(); + + for ( u32 i=0; igetAttributeCount() > 0 ) + { + core::stringw name(DefaultElementAttributes[i].TypeName.c_str()); + writer->writeElement( IRR_XML_FORMAT_GUI_ELEMENT, + false, IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE, + name.c_str() ); + + writer->writeLineBreak(); + writer->writeLineBreak(); + + DefaultElementAttributes[i].Attribute->write(writer); + writer->writeLineBreak(); + + // write closing brace + writer->writeClosingTag(IRR_XML_FORMAT_GUI_ELEMENT); + writer->writeLineBreak(); + writer->writeLineBreak(); + } + } + + // close root element + writer->writeClosingTag(IRR_XML_FORMAT_GUI_ELEMENT); + writer->writeLineBreak(); + writer->writeLineBreak(); + + writer->drop(); + file->drop(); + + return true; +} + +void CGUIEnvironment::setDefaultElementAttribute(IGUIElement* defaultElement) +{ + if ( !defaultElement ) + return; + + SDefaultElementAttribute attrib; + attrib.Type = defaultElement->getType(); + attrib.TypeName = defaultElement->getTypeName(); + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + defaultElement->serializeAttributes(attr); + attrib.Attribute = attr; + setDefaultElementAttribute(attrib); + attr->drop(); +} //! reads an element void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* parent) @@ -722,6 +992,9 @@ void CGUIEnvironment::readGUIElement(io: if (reader->getNodeType() == io::EXN_UNKNOWN) reader->read(); + if ( reader->getNodeType() == io::EXN_ELEMENT_END) + return; + if (!parent && !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) { node = this; // root @@ -760,7 +1033,21 @@ void CGUIEnvironment::readGUIElement(io: attr->read(reader, true); if (node) + { + // set the default attribute if available + u32 i; + for ( i=0; i < DefaultElementAttributes.size(); ++i ) + { + if ( DefaultElementAttributes[i].Type == node->getType() ) + { + attr->setDefaultAttributeUsage( DefaultElementAttributeUsage ); + attr->setDefaultAttributes( DefaultElementAttributes[i].Attribute ); + break; + } + } + node->deserializeAttributes(attr); + } attr->drop(); } @@ -768,7 +1055,7 @@ void CGUIEnvironment::readGUIElement(io: if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) { - readGUIElement(reader, node); + readGUIElement(reader, node ? node : parent); } else { @@ -794,9 +1081,21 @@ void CGUIEnvironment::writeGUIElement(io const wchar_t* name = 0; - // write properties - io::IAttributes* attr = FileSystem->createEmptyAttributes(); + + // set the default attribute if available + u32 i; + for ( i=0; i < DefaultElementAttributes.size(); ++i ) + { + if ( DefaultElementAttributes[i].Type == node->getType() ) + { + attr->setDefaultAttributeUsage( DefaultElementAttributeUsage ); + attr->setDefaultAttributes( DefaultElementAttributes[i].Attribute ); + break; + } + } + + // write properties node->serializeAttributes(attr); // all gui elements must have at least one attribute @@ -816,10 +1115,7 @@ void CGUIEnvironment::writeGUIElement(io } writer->writeLineBreak(); - writer->writeLineBreak(); - attr->write(writer); - writer->writeLineBreak(); } // write children @@ -907,7 +1203,7 @@ IGUIButton* CGUIEnvironment::addButton(c //! adds a window. The returned pointer must not be dropped. IGUIWindow* CGUIEnvironment::addWindow(const core::rect& rectangle, bool modal, - const wchar_t* text, IGUIElement* parent, s32 id) + const wchar_t* text, s32 flags, IGUIElement* parent, s32 id) { parent = parent ? parent : this; @@ -917,7 +1213,7 @@ IGUIWindow* CGUIEnvironment::addWindow(c parent->drop(); } - IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle); + IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle, flags); if (text) win->setText(text); win->drop(); @@ -937,7 +1233,7 @@ IGUIElement* CGUIEnvironment::addModalSc //! Adds a message box. IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t* text, - bool modal, s32 flag, IGUIElement* parent, s32 id) + bool modal, s32 flag, IGUIElement* parent, s32 id, video::ITexture* image, s32 windowflags) { if (!CurrentSkin) return 0; @@ -964,7 +1260,9 @@ IGUIWindow* CGUIEnvironment::addMessageB } IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag, - parent, id, rect); + parent, id, rect, image, windowflags); + win->setBorderStyle(2); + win->setMovable(true); win->drop(); return win; @@ -1018,6 +1316,15 @@ IGUIImage* CGUIEnvironment::addImage(con return img; } +//! Adds a GUI Rectangle +IGUIRectangle* CGUIEnvironment::addRectangle(const core::rect& rectangle, IGUIElement* parent, s32 id) +{ + IGUIRectangle * newRect = new CGUIRectangle(this, parent ? parent : this, id, rectangle); + + newRect->drop(); + + return newRect; +} //! adds an mesh viewer. The returned pointer must not be dropped. IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text) @@ -1070,6 +1377,13 @@ IGUIListBox* CGUIEnvironment::addListBox } +IGUITable* CGUIEnvironment::addTable(const core::rect& rectangle, IGUIElement* parent, s32 id, bool drawBackground) +{ + CGUITable* b = new CGUITable(this, parent ? parent : this, id, rectangle, true, drawBackground, false); + b->drop(); + return b; +} + //! adds a file open dialog. The returned pointer must not be dropped. IGUIFileOpenDialog* CGUIEnvironment::addFileOpenDialog(const wchar_t* title, @@ -1135,10 +1449,10 @@ IGUIStaticText* CGUIEnvironment::addStat //! Adds an edit box. The returned pointer must not be dropped. IGUIEditBox* CGUIEnvironment::addEditBox(const wchar_t* text, const core::rect& rectangle, - bool border, IGUIElement* parent, + bool border, bool transparent, IGUIElement* parent, s32 id) { - IGUIEditBox* d = new CGUIEditBox(text, border, this, + IGUIEditBox* d = new CGUIEditBox(text, border, transparent, this, parent ? parent : this, id, rectangle); d->drop(); @@ -1264,12 +1578,19 @@ IGUIFont* CGUIEnvironment::getFont(const else f.Filename = filename; - f.Filename.make_lower(); - s32 index = Fonts.binary_search(f); if (index != -1) return Fonts[index].Font; + // check if one of the factories can create it + for (s32 i=0; i<(int)GUIFontFactoryList.size() && !ifont; ++i) + { + ifont = GUIFontFactoryList[i]->addGUIFont(filename); + } + + // try the traditional way (without factories, but we could maybe add a default factory for this someday) + if ( !ifont ) + { // font doesn't exist, attempt to load it // does the file exist? @@ -1337,6 +1658,7 @@ IGUIFont* CGUIEnvironment::getFont(const } xml->drop(); } + } if (!ifont) @@ -1352,7 +1674,7 @@ IGUIFont* CGUIEnvironment::getFont(const } // add to fonts. - + ifont->getName() = filename; f.Font = ifont; Fonts.push_back(f); @@ -1369,8 +1691,6 @@ IGUISpriteBank* CGUIEnvironment::getSpri else b.Filename = filename; - b.Filename.make_lower(); - s32 index = Banks.binary_search(b); if (index != -1) return Banks[index].Bank; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEnvironment.h Irrlicht_starsonata/source/Irrlicht/CGUIEnvironment.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIEnvironment.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIEnvironment.h 2008-05-31 04:51:06.000000000 +0200 @@ -10,6 +10,7 @@ #include "irrArray.h" #include "IFileSystem.h" #include "IOSOperator.h" +#include "EAttributes.h" namespace irr { @@ -81,14 +82,15 @@ public: //! adds a window. The returned pointer must not be dropped. virtual IGUIWindow* addWindow(const core::rect& rectangle, bool modal = false, - const wchar_t* text=0, IGUIElement* parent=0, s32 id=-1); + const wchar_t* text=0, s32 flags=EWF_CLOSE|EWF_TITLEBAR, IGUIElement* parent=0, s32 id=-1); //! adds a modal screen. The returned pointer must not be dropped. virtual IGUIElement* addModalScreen(IGUIElement* parent); //! Adds a message box. virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, - bool modal = true, s32 flag = EMBF_OK, IGUIElement* parent=0, s32 id=-1); + bool modal = true, s32 flag = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0, + s32 windowflags=EWF_TITLEBAR); //! adds a scrollbar. The returned pointer must not be dropped. virtual IGUIScrollBar* addScrollBar(bool horizontal, const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1); @@ -101,6 +103,9 @@ public: virtual IGUIImage* addImage(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0); + //! JEFF extension adds a rectangle + virtual IGUIRectangle* addRectangle(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1); + //! adds a checkbox virtual IGUICheckBox* addCheckBox(bool checked, const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0); @@ -108,6 +113,10 @@ public: virtual IGUIListBox* addListBox(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, bool drawBackground=false); + //! Adds a table element. + virtual IGUITable* addTable(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false); + //! adds an mesh viewer. The returned pointer must not be dropped. virtual IGUIMeshViewer* addMeshViewer(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0); @@ -121,7 +130,7 @@ public: //! Adds an edit box. The returned pointer must not be dropped. virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect& rectangle, - bool border=false, IGUIElement* parent=0, s32 id=-1); + bool border=false, bool transparent=false, IGUIElement* parent=0, s32 id=-1); //! Adds a spin box to the environment virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect& rectangle, @@ -190,6 +199,17 @@ public: //! Adds a GUI Element by its name virtual IGUIElement* addGUIElement(const c8* elementName, IGUIElement* parent=0); + //! Adds a font factory to the gui environment. + /** Use this to extend the gui environment with new fonts which it should be + able to create automaticly, for example when loading data from xml files. */ + virtual void registerGUIFontFactory(IGUIFontFactory* factoryToAdd); + + //! Returns amount of registered font factories. + virtual s32 getRegisteredGUIFontFactoryCount(); + + //! Returns a font factory by index + virtual IGUIFontFactory* getGUIFontFactory(s32 index); + //! Saves the current gui into a file. /** \param filename: Name of the file. \param start: The element to start saving from. @@ -226,9 +246,27 @@ public: //! reads an element virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* parent); + //! remove default attribute settings for all element types + virtual void clearDefaultElementAttributes(); + + //! load a set of default attribute settings from a xml file + virtual bool loadDefaultElementAttributes(const c8* filename); + + //! save current default attribute settings to a xml file + virtual bool saveDefaultElementAttributes(const c8* filename); + + //! Use the settings of the given IGUIElement as default attribute settings for this element type + virtual void setDefaultElementAttribute(IGUIElement* defaultElement); + //! Set how the default attributes for elements should be used + virtual void setDefaultElementAttributeUsage(io::E_DEFAULT_ATTRIBUTE_USAGE usage); + + virtual void readDefaultElementAttribute(io::IXMLReader* reader); private: + //! get the typenumber for the elementname + EGUI_ELEMENT_TYPE getTypeFromName(const c8* name); + IGUIElement* getNextElement(bool reverse=false, bool group=false); struct SFont @@ -264,7 +302,23 @@ private: void loadBuiltInFont(); + struct SDefaultElementAttribute + { + SDefaultElementAttribute() : Type(EGUIET_ELEMENT), Attribute(0) {} + + EGUI_ELEMENT_TYPE Type; + core::stringc TypeName; + io::IAttributes * Attribute; + }; + core::array DefaultElementAttributes; + io::E_DEFAULT_ATTRIBUTE_USAGE DefaultElementAttributeUsage; + + // Set a default element attribute, overriding former attributes of the same type + // The used Attribute will be grab'ed within this function. + void setDefaultElementAttribute(const SDefaultElementAttribute& attribute); + core::array GUIElementFactoryList; + core::array GUIFontFactoryList; core::array Fonts; core::array Banks; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIFileOpenDialog.cpp Irrlicht_starsonata/source/Irrlicht/CGUIFileOpenDialog.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIFileOpenDialog.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIFileOpenDialog.cpp 2008-05-23 00:58:26.000000000 +0200 @@ -79,6 +79,7 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(c FileBox = Environment->addListBox(core::rect(10, 55, RelativeRect.getWidth()-90, 230), this, -1, true); FileBox->setSubElement(true); FileBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + FileBox->setSelectionMode( EGUI_LBS_MULTI_SELECTION ); FileBox->grab(); FileNameText = Environment->addStaticText(0, core::rect(10, 30, RelativeRect.getWidth()-90, 50), true, false, this); @@ -130,11 +131,18 @@ const wchar_t* CGUIFileOpenDialog::getFi return FileName.c_str(); } - +//! Micha, Starsonata: to allow multiple selection of files +const core::array& CGUIFileOpenDialog::getSelectedFilenames() const +{ + return FileNames; +} //! called if an event happened. bool CGUIFileOpenDialog::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + switch(event.EventType) { case EET_GUI_EVENT: @@ -162,36 +170,52 @@ bool CGUIFileOpenDialog::OnEvent(SEvent case EGET_LISTBOX_CHANGED: { - s32 selected = FileBox->getSelected(); if (FileList && FileSystem) { - if (FileList->isDirectory(selected)) - FileName = L""; - else - FileName = FileList->getFullFileName(selected); - } - } - break; - - case EGET_LISTBOX_SELECTED_AGAIN: - { s32 selected = FileBox->getSelected(); - if (FileList && FileSystem) - { if (FileList->isDirectory(selected)) { FileSystem->changeWorkingDirectoryTo(FileList->getFileName(selected)); fillListBox(); FileName = L""; + FileNames.clear(); } else { FileName = FileList->getFullFileName(selected); - return true; + + FileNames.clear(); + selected = FileBox->getNextMultiSelectedItem(-1); + while ( selected >= 0 ) + { + FileNames.push_back ( FileList->getFullFileName(selected) ); + selected = FileBox->getNextMultiSelectedItem(selected); + } } } } break; + + // Micha, Starsonata: Changing the directory already on the first click makes multiselection easier + //case EGET_LISTBOX_SELECTED_AGAIN: + // { + // s32 selected = FileBox->getSelected(); + // if (FileList && FileSystem) + // { + // if (FileList->isDirectory(selected)) + // { + // FileSystem->changeWorkingDirectoryTo(FileList->getFileName(selected)); + // fillListBox(); + // FileName = L""; + // } + // else + // { + // FileName = FileList->getFullFileName(selected); + // return true; + // } + // } + // } + // break; } break; case EET_MOUSE_INPUT_EVENT: @@ -227,7 +251,7 @@ bool CGUIFileOpenDialog::OnEvent(SEvent } } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIFileOpenDialog.h Irrlicht_starsonata/source/Irrlicht/CGUIFileOpenDialog.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIFileOpenDialog.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIFileOpenDialog.h 2007-11-22 01:29:58.000000000 +0100 @@ -28,6 +28,9 @@ namespace gui //! returns the filename of the selected file. Returns NULL, if no file was selected. virtual const wchar_t* getFilename(); + //! Micha, Starsonata: to allow multiple selection of files + virtual const core::array& getSelectedFilenames() const; + //! called if an event happened. virtual bool OnEvent(SEvent event); @@ -46,7 +49,9 @@ namespace gui void sendCancelEvent(); core::position2d DragStart; - core::stringw FileName; + core::stringw FileName; // Starsonata, Micha: this is now redundant and only kept for backward compatibility + core::array FileNames; + bool Dragging; IGUIButton* CloseButton; IGUIButton* OKButton; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIFont.cpp Irrlicht_starsonata/source/Irrlicht/CGUIFont.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIFont.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIFont.cpp 2008-04-10 19:04:40.000000000 +0200 @@ -31,6 +31,7 @@ CGUIFont::CGUIFont(IGUIEnvironment *env, Driver = Environment->getVideoDriver(); SpriteBank = Environment->addEmptySpriteBank(filename); + SpriteBank->grab(); } if (Driver) diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIImage.cpp Irrlicht_starsonata/source/Irrlicht/CGUIImage.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIImage.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIImage.cpp 2008-05-24 04:54:22.000000000 +0200 @@ -18,6 +18,9 @@ namespace gui CGUIImage::CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) : IGUIImage(environment, parent, id, rectangle), Color(255,255,255,255), Texture(0), UseAlphaChannel(false), ScaleImage(false) + , ShrinkClippingLeft(0.f), ShrinkClippingTop(0.f) + , ShrinkClippingRight(0.f), ShrinkClippingBottom(0.f) + , RotationAngle(0.f) { #ifdef _DEBUG setDebugName("CGUIImage"); @@ -38,6 +41,8 @@ CGUIImage::~CGUIImage() //! sets an image void CGUIImage::setImage(video::ITexture* image) { + if ( Texture != image ) + { if (Texture) Texture->drop(); @@ -45,6 +50,7 @@ void CGUIImage::setImage(video::ITexture if (Texture) Texture->grab(); + } } @@ -68,6 +74,34 @@ void CGUIImage::draw() if (Texture) { + core::rect rectSource; + if ( SourceRect.getWidth() ) + rectSource = SourceRect; + else + rectSource = core::rect(core::position2d(0,0), Texture->getOriginalSize()); + + // reduce the clipping area + core::rect rectClipping(AbsoluteClippingRect); + f32 clipWidth = (f32)AbsoluteClippingRect.getWidth(); + f32 clipHeight = (f32)AbsoluteClippingRect.getHeight(); + if ( ShrinkClippingLeft > 0.f ) + { + rectClipping.UpperLeftCorner.X -= s32(0.01f*ShrinkClippingLeft*clipWidth); + } + if ( ShrinkClippingTop > 0.f ) + { + rectClipping.UpperLeftCorner.Y -= s32(0.01f*ShrinkClippingTop*clipHeight); + } + if ( ShrinkClippingRight > 0.f ) + { + rectClipping.LowerRightCorner.X -= s32(0.01f*ShrinkClippingRight*clipWidth); + } + if ( ShrinkClippingBottom > 0.f ) + { + rectClipping.LowerRightCorner.Y -= s32(0.01f*ShrinkClippingBottom*clipHeight); + } + rectClipping.repair(); + if (ScaleImage) { video::SColor Colors[4]; @@ -76,15 +110,14 @@ void CGUIImage::draw() Colors[2] = Color; Colors[3] = Color; - driver->draw2DImage(Texture, AbsoluteRect, - core::rect(core::position2d(0,0), Texture->getOriginalSize()), - &AbsoluteClippingRect, Colors, UseAlphaChannel); + driver->draw2DImage(Texture, AbsoluteRect, rectSource, + &rectClipping, Colors, UseAlphaChannel, RotationAngle); } else { driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner, - core::rect(core::position2d(0,0), Texture->getOriginalSize()), - &AbsoluteClippingRect, Color, UseAlphaChannel); + rectSource, + &rectClipping, Color, UseAlphaChannel, RotationAngle); } } else @@ -146,8 +179,24 @@ void CGUIImage::deserializeAttributes(io setScaleImage(in->getAttributeAsBool("ScaleImage")); } +//! sets the image source rectangle in the texture +void CGUIImage::setSourceRect(core::rect sourceRect) +{ + SourceRect = sourceRect; +} +void CGUIImage::shrinkClippingArea(f32 left, f32 top, f32 right, f32 bottom) +{ + ShrinkClippingLeft = left; + ShrinkClippingTop = top; + ShrinkClippingRight = right; + ShrinkClippingBottom = bottom; +} +void CGUIImage::setRotationDegrees(f32 angleInDegree) +{ + RotationAngle = angleInDegree; +} } // end namespace gui } // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIImage.h Irrlicht_starsonata/source/Irrlicht/CGUIImage.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIImage.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIImage.h 2008-05-24 04:01:02.000000000 +0200 @@ -49,13 +49,30 @@ namespace gui //! Reads attributes of the element virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); + //! sets the image source rectangle in the texture + virtual void setSourceRect(core::rect sourceRect); + + // starsonata, micha + //! Reduce the area used for clipping the image + //! All values are relative in percent to total width (for left and right) and height (for top and bottom) + //! Example: To create a typical progressbar which slightly increases you will decrease the right clipping from 100 to 0. + virtual void shrinkClippingArea(f32 left, f32 top, f32 right, f32 bottom); + + // starsonata, micha + //! rotate image + virtual void setRotationDegrees(f32 angleInDegree); private: + core::rect SourceRect; video::SColor Color; video::ITexture* Texture; bool UseAlphaChannel; bool ScaleImage; - + f32 ShrinkClippingLeft; + f32 ShrinkClippingTop; + f32 ShrinkClippingRight; + f32 ShrinkClippingBottom; + f32 RotationAngle; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUIListBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIListBox.cpp 2008-06-07 11:20:00.000000000 +0200 @@ -21,10 +21,12 @@ CGUIListBox::CGUIListBox(IGUIEnvironment s32 id, core::rect rectangle, bool clip, bool drawBack, bool moveOverSelect) : IGUIListBox(environment, parent, id, rectangle), Selected(-1), ItemHeight(0), - TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), + TotalItemHeight(0), ItemsIconWidth(0), Font(0), FontUsedToWrap(0), IconBank(0), ScrollBar(0), Selecting(false), DrawBack(drawBack), - MoveOverSelect(moveOverSelect), selectTime(0), AutoScroll(true), + MoveOverSelect(moveOverSelect), selectTime(0), ScrollStyle(EGUI_LBSC_TO_SELECTED), + ScrollbarAlwaysVisible(false), KeyBuffer(), LastKeyTime(0), HighlightWhenNotFocused(true) + ,WordWrap(false), SelectionMode(EGUI_LBS_SINGLE_SELECTION) { #ifdef _DEBUG setDebugName("CGUIListBox"); @@ -39,7 +41,7 @@ CGUIListBox::CGUIListBox(IGUIEnvironment ScrollBar->setSubElement(true); ScrollBar->setTabStop(false); ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); - ScrollBar->setVisible(false); + ScrollBar->setVisible(ScrollbarAlwaysVisible); ScrollBar->drop(); ScrollBar->setPos(0); @@ -64,6 +66,9 @@ CGUIListBox::~CGUIListBox() if (Font) Font->drop(); + if ( FontUsedToWrap ) + FontUsedToWrap->drop(); + if (IconBank) IconBank->drop(); } @@ -84,7 +89,7 @@ const wchar_t* CGUIListBox::getListItem( if (id<0 || id>((s32)Items.size())-1) return 0; - return Items[id].text.c_str(); + return Items[id].Text.c_str(); } //! Returns the icon of an item @@ -93,21 +98,14 @@ s32 CGUIListBox::getIcon(s32 id) const if (id<0 || id>((s32)Items.size())-1) return -1; - return Items[id].icon; + return Items[id].Icon; } //! adds an list item, returns id of item s32 CGUIListBox::addItem(const wchar_t* text) { - ListItem i; - i.text = text; - - Items.push_back(i); - recalculateItemHeight(); - recalculateScrollPos(); - - return Items.size() - 1; + return addItem(text, -1); } //! adds an list item, returns id of item @@ -149,8 +147,10 @@ void CGUIListBox::clear() -void CGUIListBox::recalculateItemHeight() +void CGUIListBox::recalculateItemHeight(bool onlyIfFontChanged_) { + // TODO: this does ignore icons so far + IGUISkin* skin = Environment->getSkin(); if (Font != skin->getFont()) @@ -167,11 +167,26 @@ void CGUIListBox::recalculateItemHeight( Font->grab(); } } + else if ( onlyIfFontChanged_ ) + return; + if ( WordWrap ) + { + TotalItemHeight = 0; + for ( s32 i=0; i < (s32)Items.size(); ++i ) + { + TotalItemHeight += Items[i].WrappedText.size() * ItemHeight; + } + } + else + { TotalItemHeight = ItemHeight * Items.size(); + } ScrollBar->setMax(TotalItemHeight - AbsoluteRect.getHeight()); + s32 pageSize = TotalItemHeight ? core::round32((f32)ScrollBar->getMax()*((f32)AbsoluteRect.getHeight() / (f32)TotalItemHeight)) : 1; + ScrollBar->setPageSize(pageSize); - if( TotalItemHeight <= AbsoluteRect.getHeight() ) + if( TotalItemHeight <= AbsoluteRect.getHeight() && !ScrollbarAlwaysVisible ) ScrollBar->setVisible(false); else ScrollBar->setVisible(true); @@ -191,14 +206,14 @@ s32 CGUIListBox::getSelected() //! sets the selected item. Set this to -1 if no item should be selected void CGUIListBox::setSelected(s32 id) { - if (id<0 || id>((s32)Items.size())-1) + if (id<0 || id>((s32)Items.size())-1 ) Selected = -1; else Selected = id; selectTime = os::Timer::getTime(); - recalculateScrollPos(); + scrollToItem(Selected); } @@ -206,10 +221,14 @@ void CGUIListBox::setSelected(s32 id) //! called if an event happened. bool CGUIListBox::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + switch(event.EventType) { case EET_KEY_INPUT_EVENT: - if (event.KeyInput.PressedDown && + if (SelectionMode == EGUI_LBS_SINGLE_SELECTION && + event.KeyInput.PressedDown && (event.KeyInput.Key == KEY_DOWN || event.KeyInput.Key == KEY_UP || event.KeyInput.Key == KEY_HOME || @@ -247,7 +266,7 @@ bool CGUIListBox::OnEvent(SEvent event) if (Selected<0) Selected = 0; - recalculateScrollPos(); + scrollToItem(Selected); // post the news @@ -277,7 +296,8 @@ bool CGUIListBox::OnEvent(SEvent event) } return true; } - else if (event.KeyInput.PressedDown && event.KeyInput.Char) + else if (SelectionMode == EGUI_LBS_SINGLE_SELECTION && + event.KeyInput.PressedDown && event.KeyInput.Char) { // change selection based on text as it is typed. u32 now = os::Timer::getTime(); @@ -304,16 +324,16 @@ bool CGUIListBox::OnEvent(SEvent event) // dont change selection if the key buffer matches the current item if (Selected > -1 && KeyBuffer.size() > 1) { - if (Items[Selected].text.size() >= KeyBuffer.size() && - KeyBuffer.equals_ignore_case(Items[Selected].text.subString(0,KeyBuffer.size()))) + if (Items[Selected].Text.size() >= KeyBuffer.size() && + KeyBuffer.equals_ignore_case(Items[Selected].Text.subString(0,KeyBuffer.size()))) return true; } while (current < (s32)Items.size()) { - if (Items[current].text.size() >= KeyBuffer.size()) + if (Items[current].Text.size() >= KeyBuffer.size()) { - if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size()))) + if (KeyBuffer.equals_ignore_case(Items[current].Text.subString(0,KeyBuffer.size()))) { if (Parent && Selected != current && !Selecting && !MoveOverSelect) { @@ -333,9 +353,9 @@ bool CGUIListBox::OnEvent(SEvent event) current = 0; while (current <= start) { - if (Items[current].text.size() >= KeyBuffer.size()) + if (Items[current].Text.size() >= KeyBuffer.size()) { - if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size()))) + if (KeyBuffer.equals_ignore_case(Items[current].Text.subString(0,KeyBuffer.size()))) { if (Parent && Selected != current && !Selecting && !MoveOverSelect) { @@ -399,15 +419,28 @@ bool CGUIListBox::OnEvent(SEvent event) } Selecting = false; - selectNew(event.MouseInput.Y); + selectNew(event.MouseInput.Y, false, event.MouseInput.Shift, event.MouseInput.Control ); return true; + case EMIE_LMOUSE_DOUBLE_CLICK: + { + if (Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = EGET_ELEMENT_DOUBLE_CLICKED; + Parent->OnEvent(event); + } + break; + } + case EMIE_MOUSE_MOVED: - if (Selecting || MoveOverSelect) + if ( Selecting || (MoveOverSelect && SelectionMode == EGUI_LBS_SINGLE_SELECTION) ) { if (isPointInside(p)) { - selectNew(event.MouseInput.Y, true); + selectNew(event.MouseInput.Y, true, event.MouseInput.Shift, event.MouseInput.Control ); return true; } } @@ -419,25 +452,74 @@ bool CGUIListBox::OnEvent(SEvent event) } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } -void CGUIListBox::selectNew(s32 ypos, bool onlyHover) +void CGUIListBox::selectNew(s32 ypos, bool onlyHover, bool shift, bool ctrl) { + if ( SelectionMode == EGUI_LBS_NOT_SELECTABLE ) + return; s32 oldSelected = Selected; // find new selected item. if (ItemHeight!=0) - Selected = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + { + s32 selectedLine = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + + Selected = selectedLine; + if ( WordWrap ) + { + s32 lines = 0; + for ( u32 i=0; i < Items.size(); ++i) + { + lines += Items[i].WrappedText.size(); + if ( lines > selectedLine ) + { + Selected = i; + break; + } + } + } + } + + // set the multiselection flag. The other stuff like active selected can just be ignored. + if ( EGUI_LBS_MULTI_SELECTION == SelectionMode + && Selected < (s32)Items.size() + ) + { + if ( shift ) + { + clearAllItemMultiSelections(); + s32 start = core::min_(Selected, oldSelected); + if ( start < 0 ) + start = 0; + s32 end = core::max_(Selected, oldSelected); + if ( end >= (s32)Items.size() ) + end = Items.size()-1; + for ( s32 i=start; i <= end; ++i ) + { + Items[i].IsMultiSelected = true; + } + Selected = oldSelected; // Selection does not change when shift is pressed + } + else if ( ctrl ) + { + Items[Selected].IsMultiSelected = Items[Selected].IsMultiSelected ? false : true; + } + else + { + clearAllItemMultiSelections(); + Items[Selected].IsMultiSelected = true; + } + } if (Selected >= (s32)Items.size()) Selected = Items.size() - 1; - else - if (Selected<0) + else if (Selected<0) Selected = 0; - recalculateScrollPos(); + scrollToItem(Selected); // post the news if (Parent && !onlyHover) @@ -446,7 +528,7 @@ void CGUIListBox::selectNew(s32 ypos, bo 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; + event.GUIEvent.EventType = (Selected != oldSelected) || (EGUI_LBS_MULTI_SELECTION == SelectionMode) ? EGET_LISTBOX_CHANGED : EGET_LISTBOX_SELECTED_AGAIN; Parent->OnEvent(event); } } @@ -457,6 +539,7 @@ void CGUIListBox::updateAbsolutePosition IGUIElement::updateAbsolutePosition(); recalculateItemHeight(); + wrapAllText(); } //! draws the element and its children @@ -465,7 +548,12 @@ void CGUIListBox::draw() if (!IsVisible) return; - recalculateItemHeight(); // if the font changed + if ( FontUsedToWrap != Font && WordWrap ) + { + wrapAllText(); + } + + recalculateItemHeight(true); IGUISkin* skin = Environment->getSkin(); @@ -474,8 +562,6 @@ void CGUIListBox::draw() // draw background core::rect frameRect(AbsoluteRect); - // draw items - core::rect clientClip(AbsoluteRect); clientClip.UpperLeftCorner.Y += 1; clientClip.UpperLeftCorner.X += 1; @@ -484,9 +570,13 @@ void CGUIListBox::draw() clientClip.LowerRightCorner.Y -= 1; clientClip.clipAgainst(AbsoluteClippingRect); - skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, + video::SColor backgroundCol = BackgroundOverrideColor.Use ? BackgroundOverrideColor.Color : skin->getColor(EGDC_3D_HIGH_LIGHT); + + skin->draw3DSunkenPane(this, backgroundCol, true, DrawBack, frameRect, &clientClip); + // draw items + if (clipRect) clientClip.clipAgainst(*clipRect); @@ -495,46 +585,84 @@ void CGUIListBox::draw() if (ScrollBar->isVisible()) frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); - frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; - frameRect.UpperLeftCorner.Y -= ScrollBar->getPos(); - frameRect.LowerRightCorner.Y -= ScrollBar->getPos(); bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar)); for (s32 i=0; i<(s32)Items.size(); ++i) { + bool highlightSelected = (SelectionMode != EGUI_LBS_MULTI_SELECTION && i == Selected && hl) + || (SelectionMode == EGUI_LBS_MULTI_SELECTION && Items[i].IsMultiSelected ); + + if ( WordWrap ) + { + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + ItemHeight * Items[i].WrappedText.size(); + } + else + { + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + ItemHeight; + } + if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) { - if (i == Selected && hl) + if ( highlightSelected ) + { skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip); + } core::rect textRect = frameRect; textRect.UpperLeftCorner.X += 3; - if (Font) - { - if (IconBank && (Items[i].icon > -1)) + if (IconBank && (Items[i].Icon > -1)) { core::position2di iconPos = textRect.UpperLeftCorner; iconPos.Y += textRect.getHeight() / 2; iconPos.X += ItemsIconWidth/2; - IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, - skin->getColor((i==Selected && hl) ? EGDC_ICON_HIGH_LIGHT : EGDC_ICON), - (i==Selected && hl) ? selectTime : 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); + + if ( highlightSelected ) + { + IconBank->draw2DSprite( (u32)Items[i].Icon, iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ? getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT), + selectTime, os::Timer::getTime(), false, true); + } + else + { + IconBank->draw2DSprite( (u32)Items[i].Icon, iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON), + 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); + } } + if (Font) + { textRect.UpperLeftCorner.X += ItemsIconWidth+3; - Font->draw(Items[i].text.c_str(), textRect, skin->getColor((i==Selected && hl) ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT), false, true, &clientClip); + video::SColor textCol; + if ( highlightSelected ) + textCol = hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ? getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT); + else + textCol = hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT); + + if ( WordWrap ) + { + for ( u32 w=0; w < Items[i].WrappedText.size(); ++w ) + { + textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + ItemHeight; + Font->draw(Items[i].WrappedText[w].c_str(), textRect, textCol, false, true, &clientClip); + textRect.UpperLeftCorner.Y = textRect.LowerRightCorner.Y; + } + } + else + { + Font->draw(Items[i].Text.c_str(), textRect, textCol, false, true, &clientClip); + } textRect.UpperLeftCorner.X -= ItemsIconWidth+3; } } - frameRect.UpperLeftCorner.Y += ItemHeight; - frameRect.LowerRightCorner.Y += ItemHeight; + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y; } IGUIElement::draw(); @@ -546,29 +674,29 @@ void CGUIListBox::draw() s32 CGUIListBox::addItem(const wchar_t* text, s32 icon) { ListItem i; - i.text = text; - i.icon = icon; + i.Text = text; + i.Icon = icon; + + if ( WordWrap ) + wrapText(i); + + bool scrollOnChat = ScrollStyle == EGUI_LBSC_CHATLIKE && ScrollBar->getPos() == ScrollBar->getMax(); Items.push_back(i); recalculateItemHeight(); + recalculateItemWidth(icon); - if (IconBank && icon > -1 && - IconBank->getSprites().size() > (u32)icon && - IconBank->getSprites()[(u32)icon].Frames.size()) - { - u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; - if (IconBank->getPositions().size() > rno) + if ( ScrollStyle == EGUI_LBSC_TO_ADDED + || ScrollStyle == EGUI_LBSC_TO_ACTIVE + || scrollOnChat + ) { - const s32 w = IconBank->getPositions()[rno].getWidth(); - if (w > ItemsIconWidth) - ItemsIconWidth = w; - } + ScrollBar->setPos(ScrollBar->getMax()); } return Items.size() - 1; } - void CGUIListBox::setSpriteBank(IGUISpriteBank* bank) { if (IconBank) @@ -578,33 +706,83 @@ void CGUIListBox::setSpriteBank(IGUISpri if (IconBank) IconBank->grab(); } -void CGUIListBox::recalculateScrollPos() + +void CGUIListBox::scrollToItem(s32 itemId) { - if (!AutoScroll) + if (ScrollStyle == EGUI_LBSC_MANUAL || ScrollStyle == EGUI_LBSC_TO_ADDED) return; - s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos(); + // height from top of list if the complete list would be visible + s32 selectedItemHeight = itemId < 0 ? 0 : itemId * ItemHeight; + if ( WordWrap && itemId >= 0 ) + { + selectedItemHeight = 0; + for ( s32 i=0; igetPos(); if (selPos < 0) { ScrollBar->setPos(ScrollBar->getPos() + selPos); } - else - if (selPos > AbsoluteRect.getHeight() - ItemHeight) + else if (selPos > AbsoluteRect.getHeight() - ItemHeight) { ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight); } } -void CGUIListBox::setAutoScrollEnabled(bool scroll) +void CGUIListBox::setScrollStyle( EGUI_LISTBOX_SCROLLING style) { - AutoScroll = scroll; + ScrollStyle = style; } -bool CGUIListBox::isAutoScrollEnabled() +EGUI_LISTBOX_SCROLLING CGUIListBox::getScrollStyle() const { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return AutoScroll; + return ScrollStyle; +} + +void CGUIListBox::setScrollbarAlwaysVisible(bool always_) +{ + ScrollbarAlwaysVisible = always_; + if ( ScrollbarAlwaysVisible && ScrollBar ) + { + ScrollBar->setVisible(true); + } +} + +bool CGUIListBox::isScrollbarAlwaysVisible() const +{ + return ScrollbarAlwaysVisible; +} + +bool CGUIListBox::getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) +{ + switch ( colorType ) + { + case EGUI_LBC_TEXT: + useColorLabel = "UseColText"; + colorLabel = "ColText"; + break; + case EGUI_LBC_TEXT_HIGHLIGHT: + useColorLabel = "UseColTextHl"; + colorLabel = "ColTextHl"; + break; + case EGUI_LBC_ICON: + useColorLabel = "UseColIcon"; + colorLabel = "ColIcon"; + break; + case EGUI_LBC_ICON_HIGHLIGHT: + useColorLabel = "UseColIconHl"; + colorLabel = "ColIconHl"; + break; + default: + return false; + } + return true; } //! Writes attributes of the element. @@ -615,16 +793,50 @@ void CGUIListBox::serializeAttributes(io // todo: out->addString ("IconBank", IconBank->getName?); out->addBool ("DrawBack", DrawBack); out->addBool ("MoveOverSelect", MoveOverSelect); - out->addBool ("AutoScroll", AutoScroll); + out->addEnum ("ScrollStyle", ScrollStyle, GUIListBoxScrollingNames ); + out->addBool ("ScrollbarAlwaysVisible", ScrollbarAlwaysVisible); + out->addBool ("WordWrap", WordWrap); + out->addEnum ("SelectionMode", SelectionMode, GUIListBoxSelectionNames ); - // todo: save list of items and icons. + // StarSonata, Micha: + // I also don't know yet how to handle icons, but added some text+color serialization now + // I did it the same way it's done for the context menus + out->addInt("ItemCount", Items.size()); + u32 i; + for (i=0;iaddString(label.c_str(), Items[i].Text.c_str() ); + + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + core::stringc useColorLabel, colorLabel; + if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) ) + return; + label = useColorLabel; label += i; + if ( Items[i].OverrideColors[c].Use ) + { + out->addBool(label.c_str(), true ); + label = colorLabel; label += i; + out->addColor(label.c_str(), Items[i].OverrideColors[c].Color); + } + else + { + out->addBool(label.c_str(), false ); + } + } + } + + // todo: icons. /*core::array tmpText; core::array tmpIcons; u32 i; for (i=0;iaddArray ("ItemText", tmpText); @@ -638,12 +850,51 @@ void CGUIListBox::serializeAttributes(io //! Reads attributes of the element void CGUIListBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { + clear(); + DrawBack = in->getAttributeAsBool("DrawBack"); MoveOverSelect = in->getAttributeAsBool("MoveOverSelect"); - AutoScroll = in->getAttributeAsBool("AutoScroll"); + ScrollStyle = (EGUI_LISTBOX_SCROLLING) in->getAttributeAsEnumeration("ScrollStyle", GUIListBoxScrollingNames); + ScrollbarAlwaysVisible = in->getAttributeAsBool("ScrollbarAlwaysVisible"); + WordWrap = in->getAttributeAsBool("WordWrap"); + SelectionMode = (EGUI_LISTBOX_SELECTION) in->getAttributeAsEnumeration("SelectionMode", GUIListBoxSelectionNames ); IGUIListBox::deserializeAttributes(in,options); + // StarSonata, Micha: + // I also don't know yet how to handle icons, but added some text+color serialization now + // I did it the same way it's done for the context menus + s32 count = in->getAttributeAsInt("ItemCount"); + for (s32 i=0; i<(s32)count; ++i) + { + core::stringc label; + ListItem item; + + label = "text"; label += i; + item.Text = in->getAttributeAsStringW(label.c_str()); + + addItem(item.Text.c_str(), item.Icon); + + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + core::stringc useColorLabel, colorLabel; + if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) ) + return; + label = useColorLabel; label += i; + Items[i].OverrideColors[c].Use = in->getAttributeAsBool(label.c_str()); + if ( Items[i].OverrideColors[c].Use ) + { + label = colorLabel; label += i; + Items[i].OverrideColors[c].Color = in->getAttributeAsColor(label.c_str()); + } + } + } + + if ( WordWrap ) + { + wrapAllText(); + } + // read arrays /* core::array tmpText; @@ -660,6 +911,392 @@ void CGUIListBox::deserializeAttributes( } +void CGUIListBox::recalculateItemWidth(s32 icon) +{ + if (IconBank && icon > -1 && + IconBank->getSprites().size() > (u32)icon && + IconBank->getSprites()[(u32)icon].Frames.size()) + { + u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; + if (IconBank->getPositions().size() > rno) + { + const s32 w = IconBank->getPositions()[rno].getWidth(); + if (w > ItemsIconWidth) + ItemsIconWidth = w; + } + } +} + +void CGUIListBox::setItem(s32 index, const wchar_t* text, s32 icon) +{ + if ( index < 0 || index >= (s32)Items.size() ) + return; + + Items[index].Text = text; + Items[index].Icon = icon; + + if ( WordWrap ) + wrapText(Items[index]); + + recalculateItemHeight(); + recalculateItemWidth(icon); +} + +//! Insert the item at the given index +//! Return the index on success or -1 on failure. +s32 CGUIListBox::insertItem(s32 index, const wchar_t* text, s32 icon) +{ + if ( index < 0 ) + return -1; + ListItem i; + i.Text = text; + i.Icon = icon; + + if ( WordWrap ) + wrapText(i); + + Items.insert(i, index); + recalculateItemHeight(); + recalculateItemWidth(icon); + + if ( ScrollStyle == EGUI_LBSC_TO_ADDED + || ScrollStyle == EGUI_LBSC_TO_ACTIVE + || ScrollStyle == EGUI_LBSC_CHATLIKE + ) + { + scrollToItem(index); + } + + return index; +} + +void CGUIListBox::swapItems(s32 index1, s32 index2) +{ + if ( index1 < 0 || index2 < 0 || index1 >= (s32)Items.size() || index2 >= (s32)Items.size() ) + return; + + ListItem dummmy = Items[index1]; + Items[index1] = Items[index2]; + Items[index2] = dummmy; +} + +void CGUIListBox::setBackgroundOverrideColor(const video::SColor &color, bool includeScrollbar) +{ + BackgroundOverrideColor.Use = true; + BackgroundOverrideColor.Color = color; + + if ( includeScrollbar && ScrollBar ) + { + ScrollBar->setBackgroundOverrideColor(color); + } +} + +void CGUIListBox::clearBackgroundOverrideColor(bool includeScrollbar) +{ + BackgroundOverrideColor.Use = false; + if ( includeScrollbar && ScrollBar ) + { + ScrollBar->clearBackgroundOverrideColor(); + } +} + +void CGUIListBox::setItemOverrideColor(s32 index, const video::SColor &color) +{ + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + Items[index].OverrideColors[c].Use = true; + Items[index].OverrideColors[c].Color = color; + } +} + +void CGUIListBox::setItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType, const video::SColor &color) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return; + + Items[index].OverrideColors[colorType].Use = true; + Items[index].OverrideColors[colorType].Color = color; +} + +void CGUIListBox::clearItemOverrideColor(s32 index) +{ + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + Items[index].OverrideColors[c].Use = false; + } +} + +void CGUIListBox::clearItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return; + + Items[index].OverrideColors[colorType].Use = false; +} + +bool CGUIListBox::hasItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return false; + + return Items[index].OverrideColors[colorType].Use; +} + +video::SColor CGUIListBox::getItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return video::SColor(); + + return Items[index].OverrideColors[colorType].Color; +} + +video::SColor CGUIListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) +{ + IGUISkin* skin = Environment->getSkin(); + if ( !skin ) + return video::SColor(); + + switch ( colorType ) + { + case EGUI_LBC_TEXT: + return skin->getColor(EGDC_BUTTON_TEXT); + case EGUI_LBC_TEXT_HIGHLIGHT: + return skin->getColor(EGDC_HIGH_LIGHT_TEXT); + case EGUI_LBC_ICON: + return skin->getColor(EGDC_ICON); + case EGUI_LBC_ICON_HIGHLIGHT: + return skin->getColor(EGDC_ICON_HIGH_LIGHT); + default: + return video::SColor(); + } +} + +// TODO: This can't handle text without whitespaces. +// TODO: this is mostly copied from CGUIEditBox::breakText +// This part _should_ be an own class. For example CSplitTextLines. +// But that needs some more talk with the irrlicht guys and they are currently +// to busy getting 1.4 out which is already in beta, so this has to wait. +// So for now I put it in here (because I need it for the listbox) and made it at least a little more general so it can +// be moved to some other place without so much trouble later on. +void CGUIListBox::breakText( const core::stringw &origText, s32 maxWidth, gui::IGUIFont* font, bool wordWrap, bool multiLine, core::array &brokenText, core::array &brokenTextPositions) +{ + if ((!wordWrap && !multiLine) || !font || maxWidth <= 0) + { + brokenText.push_back(origText); + return; + } + + brokenText.clear(); // need to reallocate :/ + brokenTextPositions.set_used(0); + + core::stringw text(origText); // we need that currently because of windows break handling :( + core::stringw line; + core::stringw word; + core::stringw whitespace; + s32 lastLineStart = 0; + s32 size = origText.size(); + s32 length = 0; + wchar_t c; + + for (s32 i=0; igetDimension(whitespace.c_str()).Width; + s32 worldlgth = font->getDimension(word.c_str()).Width; + + if (wordWrap && length + worldlgth + whitelgth > maxWidth) + { + // break to next line + length = worldlgth; + brokenText.push_back(line); + brokenTextPositions.push_back(lastLineStart); + lastLineStart = i - (s32)word.size(); + line = word; + } + else + { + // add word to line + line += whitespace; + line += word; + length += whitelgth + worldlgth; + } + + word = L""; + whitespace = L""; + } + + whitespace += c; + + // compute line break + if (lineBreak) + { + line += whitespace; + line += word; + brokenText.push_back(line); + brokenTextPositions.push_back(lastLineStart); + lastLineStart = i+1; + line = L""; + word = L""; + whitespace = L""; + length = 0; + } + } + else + { + // yippee this is a word.. + word += c; + } + } + + line += whitespace; + line += word; + brokenText.push_back(line); + brokenTextPositions.push_back(lastLineStart); +} + +// create wrapped text for all lines +void CGUIListBox::wrapAllText() +{ + for ( s32 i = 0; i < (s32)Items.size(); ++i ) + { + wrapText(Items[i]); + } +} + +void CGUIListBox::wrapText( ListItem & item ) +{ + if ( FontUsedToWrap != Font ) + { + if ( FontUsedToWrap ) + FontUsedToWrap->drop(); + FontUsedToWrap = Font; + FontUsedToWrap->grab(); + } + + core::array brokenTextPositions; // we don't need it here + + // the reduction by 7 was calculated by adding the pixels by which the width is reduced in draw + s32 maxWidth = AbsoluteRect.getWidth()-(ItemsIconWidth+7); + if (ScrollBar->isVisible()) + maxWidth -= Environment->getSkin()->getSize(EGDS_SCROLLBAR_SIZE); + + breakText( item.Text, maxWidth, FontUsedToWrap, WordWrap, /*bool multiLine*/ true, item.WrappedText, brokenTextPositions); +} + +void CGUIListBox::setWordWrap(bool enable) +{ + if ( enable == WordWrap ) + return; + + WordWrap = enable; + if ( WordWrap ) + { + wrapAllText(); + } +} + +bool CGUIListBox::isWordWrapEnabled() +{ + return WordWrap; +} + +void CGUIListBox::setSelectionMode(EGUI_LISTBOX_SELECTION selection) +{ + SelectionMode = selection; + if ( SelectionMode != EGUI_LBS_SINGLE_SELECTION ) + setSelected(-1); +} + +EGUI_LISTBOX_SELECTION CGUIListBox::getSelectionMode() const +{ + return SelectionMode; +} + +//! Get the number of items which are currently selected +//! This works only in EGUI_LBS_MULTI_SELECTION mode +s32 CGUIListBox::getMultiSelectedItemCount() const +{ + s32 count = 0; + for ( s32 i = 0; i < (s32)Items.size(); ++i ) + if ( Items[i].IsMultiSelected ) + ++count; + + return count; +} + +//! Get the id of the next item with set selection flag +//! returns the first item with selection flag when id=-1 +//! return -1 when no item was found +//! This works only in EGUI_LBS_MULTI_SELECTION mode +s32 CGUIListBox::getNextMultiSelectedItem(s32 id) +{ + for ( s32 i = id+1; i < (s32)Items.size(); ++i ) + if ( Items[i].IsMultiSelected ) + return i; + + return -1; +} + +//! Set the selection flag for the item with given id +//! Usually that will be done automatically when the users clicks. +//! This works only in EGUI_LBS_MULTI_SELECTION mode +void CGUIListBox::setItemMultiSelection(s32 id, bool selected) +{ + if ( id < 0 || id >= (s32)Items.size() ) + return; + + Items[id].IsMultiSelected = selected; +} + +//! Get the selection flag for the item with given id +//! This works only in EGUI_LBS_MULTI_SELECTION mode +bool CGUIListBox::getItemMultiSelection(s32 id) const +{ + if ( id < 0 || id >= (s32)Items.size() ) + return false; + + return Items[id].IsMultiSelected; +} + +//! Clear the selection flags for all items +//! This works only in EGUI_LBS_MULTI_SELECTION mode +void CGUIListBox::clearAllItemMultiSelections() +{ + for ( s32 i = 0; i < (s32)Items.size(); ++i ) + Items[i].IsMultiSelected = false; +} + + +// -------------------------------------------------------- + } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.h Irrlicht_starsonata/source/Irrlicht/CGUIListBox.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIListBox.h 2008-06-06 07:03:10.000000000 +0200 @@ -71,11 +71,27 @@ namespace gui //! skin through getIcon virtual void setSpriteBank(IGUISpriteBank* bank); - //! sets if automatic scrolling is enabled or not. Default is true. - virtual void setAutoScrollEnabled(bool scroll); + //! StarSonata, Micha: instead of setAutoScrollEnabled + //! Define when and how the listbox should scroll automaticaly + virtual void setScrollStyle( EGUI_LISTBOX_SCROLLING style=EGUI_LBSC_TO_SELECTED); - //! returns true if automatic scrolling is enabled, false if not. - virtual bool isAutoScrollEnabled(); + //! StarSonata, Micha: instead of isAutoScrollEnabled + //! Get when and how the listbox will scroll automaticaly + virtual EGUI_LISTBOX_SCROLLING getScrollStyle() const; + + //! StarSonata, Micha: replacing recalculateScrollPos + //! Scroll the listbox until the item with the given id is visible + virtual void scrollToItem(s32 itemId); + + // StarSonata, Micha: scrollbar visibility + //! Show scrollbar all the time. + //! By default it's only visible when so many items are in the listbox that + //! scrolling will be needed. + virtual void setScrollbarAlwaysVisible(bool always_); + + // StarSonata, Micha: multicolor support + //! is the scrollbar set to be visible all the time? + virtual bool isScrollbarAlwaysVisible() const; //! Update the position and size of the listbox, and update the scrollbar virtual void updateAbsolutePosition(); @@ -86,19 +102,138 @@ namespace gui //! Reads attributes of the element virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color, bool includeScrollbar); + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(bool includeScrollbar); + + // StarSonata, Micha: multicolor support + //! set all item colors at given index to color + virtual void setItemOverrideColor(s32 index, const video::SColor &color); + + //! set all item colors of specified type at given index to color + virtual void setItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType, const video::SColor &color); + + //! clear all item colors at index + virtual void clearItemOverrideColor(s32 index); + + //! clear item color at index for given colortype + virtual void clearItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType); + + //! has the item at index it's color overwritten? + virtual bool hasItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType); + + //! return the overwrite color at given item index. + virtual video::SColor getItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType); + + //! return the default color which is used for the given colorType + virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType); + + //! set the item at the given index + virtual void setItem(s32 index, const wchar_t* text, s32 icon); + + //! Insert the item at the given index + //! Return the index on success or -1 on failure. + virtual s32 insertItem(s32 index, const wchar_t* text, s32 icon); + + //! Swap the items at the given indices + virtual void swapItems(s32 index1, s32 index2); + + //! Enables or disables word wrap. Default is disabled. + /** \param enable: If set to true, words going over one line are + broken to the next line. */ + virtual void setWordWrap(bool enable); + + //! Checks if word wrap is enabled + //! \return true if word wrap is enabled, false otherwise + virtual bool isWordWrapEnabled(); + + //! Set the current selection mode for the listbox lines + virtual void setSelectionMode(EGUI_LISTBOX_SELECTION selection); + + //! Get the current selection mode for the listbox lines + virtual EGUI_LISTBOX_SELECTION getSelectionMode() const; + + //! Get the number of items which are currently selected + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual s32 getMultiSelectedItemCount() const; + + //! Get the id of the next item with set selection flag + //! returns the first item with selection flag when id=-1 + //! return -1 when no item was found + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual s32 getNextMultiSelectedItem(s32 id=-1); + + //! Set the selection flag for the item with given id + //! Usually that will be done automatically when the users clicks. + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void setItemMultiSelection(s32 id, bool selected); + + //! Get the selection flag for the item with given id + //! return true when the item is selected, otherwise returns false + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual bool getItemMultiSelection(s32 id) const; + + //! Clear the selection flags for all items + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void clearAllItemMultiSelections(); + + //! Access the scrollbar + virtual IGUIScrollBar* getScrollBar() const { return ScrollBar; } + private: + struct OverrideColor + { + OverrideColor() : Use(false) {} + bool Use; + video::SColor Color; + }; + struct ListItem { - ListItem() : icon(-1) {} + ListItem() : Icon(-1), IsMultiSelected(false) + {} - core::stringw text; - s32 icon; + core::stringw Text; + s32 Icon; + OverrideColor OverrideColors[EGUI_LBC_SIZE]; + + // StarSonata, Micha: + // flag used in multiselection + bool IsMultiSelected; + + // StarSonata, Micha: + // extension for wrapped text + core::array< core::stringw > WrappedText; }; - void recalculateItemHeight(); - void selectNew(s32 ypos, bool onlyHover=false); - void recalculateScrollPos(); + void recalculateItemHeight(bool onlyIfFontChanged_=false); + void selectNew(s32 ypos, bool onlyHover=false, bool shift=false, bool ctrl=false); + + // extracted that function to avoid copy&paste code + void recalculateItemWidth(s32 icon); + + // get labels used for serialization + bool getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel); + + // create wrapped text for all lines + void wrapAllText(); + void wrapText( ListItem & item); + + //! break Split text into several lines + // TODO: this should be a common function, for example in font, skin or iguielement + //! \param origText Text which should be split + //! \param maxWidth Width in pixels available for text. + //! \param font Font used to print the text + //! \param wordWrap Wrap into several lines if one line is too long. Prefer wrapping on whitespace. + //! \param multiLine Handle linebreaks like '\n' and '\r' + //! \param brokenText return the text split in several lines + //! \param brokenTextPosition return the positions at which the original text was splitted + void breakText( const core::stringw &origText, s32 maxWidth, gui::IGUIFont* font, bool wordWrap, bool multiLine, core::array &brokenText, core::array &brokenTextPosition); core::array< ListItem > Items; s32 Selected; @@ -106,16 +241,21 @@ namespace gui s32 TotalItemHeight; s32 ItemsIconWidth; gui::IGUIFont* Font; + gui::IGUIFont* FontUsedToWrap; gui::IGUISpriteBank* IconBank; gui::IGUIScrollBar* ScrollBar; bool Selecting; bool DrawBack; bool MoveOverSelect; u32 selectTime; - bool AutoScroll; + EGUI_LISTBOX_SCROLLING ScrollStyle; + bool ScrollbarAlwaysVisible; core::stringw KeyBuffer; u32 LastKeyTime; bool HighlightWhenNotFocused; + bool WordWrap; + EGUI_LISTBOX_SELECTION SelectionMode; + OverrideColor BackgroundOverrideColor; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMenu.cpp Irrlicht_starsonata/source/Irrlicht/CGUIMenu.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMenu.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIMenu.cpp 2008-03-19 17:47:42.000000000 +0100 @@ -91,7 +91,7 @@ void CGUIMenu::draw() bool CGUIMenu::OnEvent(SEvent event) { if (!IsEnabled) - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); switch(event.EventType) { @@ -100,52 +100,55 @@ bool CGUIMenu::OnEvent(SEvent event) { case gui::EGET_ELEMENT_FOCUS_LOST: if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element)) + { closeAllSubMenus(); + HighLighted = -1; + } break; case gui::EGET_ELEMENT_FOCUSED: if (event.GUIEvent.Caller == this && Parent) + { Parent->bringToFront(this); - + } + break; } break; case EET_MOUSE_INPUT_EVENT: switch(event.MouseInput.Event) { - case EMIE_LMOUSE_LEFT_UP: + case EMIE_LMOUSE_PRESSED_DOWN: { - core::position2d p(event.MouseInput.X, event.MouseInput.Y); - if (AbsoluteClippingRect.isPointInside(p)) + if (!Environment->hasFocus(this)) { - if (HighLighted != -1) - Environment->removeFocus(this); - else - highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y)); + Environment->setFocus(this); } - else + if (Parent) + Parent->bringToFront(this); + + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + bool shouldCloseSubMenu = hasOpenSubMenu(); + if (!AbsoluteClippingRect.isPointInside(p)) { + shouldCloseSubMenu = false; s32 t = sendClick(p); if ((t==0 || t==1) && Environment->hasFocus(this)) Environment->removeFocus(this); } - } + highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), true); + if ( shouldCloseSubMenu ) + closeAllSubMenus(); + return true; - case EMIE_LMOUSE_PRESSED_DOWN: - if (!Environment->hasFocus(this)) - { - Environment->setFocus(this); - if (Parent) - Parent->bringToFront(this); } - return true; case EMIE_MOUSE_MOVED: if (Environment->hasFocus(this)) - highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y)); - return true; + highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), hasOpenSubMenu()); + return false; } break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } @@ -227,17 +230,6 @@ core::rect CGUIMenu::getRect(const return getHRect(i, absolute); } - -void CGUIMenu::closeAllSubMenus() -{ - for (s32 i=0; i<(s32)Items.size(); ++i) - if (Items[i].SubMenu) - Items[i].SubMenu->setVisible(false); - - HighLighted = -1; -} - - void CGUIMenu::updateAbsolutePosition() { if (Parent) diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMenu.h Irrlicht_starsonata/source/Irrlicht/CGUIMenu.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMenu.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIMenu.h 2007-10-22 18:56:54.000000000 +0200 @@ -41,9 +41,6 @@ namespace gui //! Gets drawing rect of Item virtual core::rect getRect(const SItem& i, const core::rect& absolute); - - void closeAllSubMenus(); - }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMeshViewer.cpp Irrlicht_starsonata/source/Irrlicht/CGUIMeshViewer.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMeshViewer.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIMeshViewer.cpp 2008-03-19 17:50:04.000000000 +0100 @@ -86,7 +86,7 @@ const video::SMaterial& CGUIMeshViewer:: //! called if an event happened. bool CGUIMeshViewer::OnEvent(SEvent event) { - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMessageBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUIMessageBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMessageBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIMessageBox.cpp 2008-02-26 04:27:40.000000000 +0100 @@ -7,6 +7,8 @@ #include "IGUIEnvironment.h" #include "IGUIButton.h" #include "IGUIFont.h" +#include "IGUIImage.h" +#include "ITexture.h" namespace irr { @@ -15,11 +17,13 @@ namespace gui //! constructor CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption, - const wchar_t* text, s32 flags, - IGUIElement* parent, s32 id, core::rect rectangle) -: CGUIWindow(environment, parent, id, rectangle), + const wchar_t* text, s32 boxflags, + IGUIElement* parent, s32 id, core::rect rectangle, + video::ITexture* image, s32 windowflags) +: CGUIWindow(environment, parent, id, rectangle, windowflags), OkButton(0), CancelButton(0), YesButton(0), NoButton(0), StaticText(0), - Flags(flags), MessageText(text), Pressed(false) + BoxFlags(boxflags), MessageText(text), Pressed(false) + , Icon(0), IconTexture(image) { #ifdef _DEBUG setDebugName("CGUIMessageBox"); @@ -41,76 +45,136 @@ CGUIMessageBox::CGUIMessageBox(IGUIEnvir Environment->setFocus(this); + if ( IconTexture ) + IconTexture->grab(); + refreshControls(); } void CGUIMessageBox::refreshControls() { + // Layout can be seen as 4 boxes (a layoutmanager would be nice...) + // One box at top over the whole width for title + // Two boxes with same height at the middle beside each other for icon and for text + // One box at the bottom for the buttons + IGUISkin* skin = Environment->getSkin(); IGUIElement* focusMe = 0; s32 buttonHeight = skin->getSize(EGDS_BUTTON_HEIGHT); s32 buttonWidth = skin->getSize(EGDS_BUTTON_WIDTH); - s32 titleHeight = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2; + s32 titleHeight = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2; //MICHA: it seems the titlebar has no own constant yet. Rather strange... s32 buttonDistance = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + s32 borderWidth = buttonDistance; // MICHA: Clear Borders at sides and between icon-text and between content-buttons A constant in the skin for that would be nicer. - // add static multiline text - - core::dimension2d dim(AbsoluteClippingRect.getWidth() - buttonWidth, - AbsoluteClippingRect.getHeight() - (buttonHeight * 3)); - core::position2d pos((AbsoluteClippingRect.getWidth() - dim.Width) / 2, - buttonHeight / 2 + titleHeight); - + // add the static text first using the maximum possible size + // We need to do so, because it's at the moment the only way to find out the size which text will need. + // A common class or function (outside statictext) to calculate textsplitting + needed textarea should be done someday if (!StaticText) { - StaticText = Environment->addStaticText(MessageText.c_str(), - core::rect(pos, dim), false, false, this); + core::rect staticRect; + staticRect.UpperLeftCorner.X = borderWidth; + staticRect.UpperLeftCorner.Y = titleHeight + borderWidth; + staticRect.LowerRightCorner.X = getRelativePosition().getWidth() - borderWidth; + staticRect.LowerRightCorner.Y = getRelativePosition().getHeight() - borderWidth; + + StaticText = Environment->addStaticText(MessageText.c_str(), staticRect, false, false, this); StaticText->setWordWrap(true); StaticText->setSubElement(true); StaticText->grab(); } else { - StaticText->setRelativePosition( core::rect(pos, dim)); + StaticText->setRelativePosition( AbsoluteClippingRect ); StaticText->setText(MessageText.c_str()); } - // adjust static text height - s32 textHeight = StaticText->getTextHeight(); - core::rect tmp = StaticText->getRelativePosition(); - tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + textHeight; - StaticText->setRelativePosition(tmp); - dim.Height = textHeight; + s32 textWidth = StaticText->getTextWidth() + 6; // +6 because the static itself needs that + s32 iconHeight = IconTexture ? IconTexture->getOriginalSize().Height : 0; - // adjust message box height + // content is text + icons + borders (but not titlebar) + s32 contentHeight = textHeight > iconHeight ? textHeight : iconHeight; + contentHeight += borderWidth; + s32 contentWidth = 0; - tmp = getRelativePosition(); - s32 msgBoxHeight = textHeight + (s32)(2.5f * buttonHeight) + titleHeight; + // add icon + if ( IconTexture ) + { + core::position2d iconPos; + iconPos.Y = titleHeight + borderWidth; + if ( iconHeight < textHeight ) + iconPos.Y += (textHeight-iconHeight) / 2; + iconPos.X = borderWidth; - // adjust message box position + if (!Icon) + { + Icon = Environment->addImage(IconTexture, iconPos, true, this); + Icon->setSubElement(true); + Icon->grab(); + } + else + { + core::rect iconRect( iconPos.X, iconPos.Y, iconPos.X + IconTexture->getOriginalSize().Width, iconPos.Y + IconTexture->getOriginalSize().Height ); + Icon->setRelativePosition(iconRect); + } + + contentWidth += borderWidth + IconTexture->getOriginalSize().Width; + } + else if ( Icon ) + { + Icon->drop(); + Icon->remove(); + Icon = 0; + } + // position text + core::rect textRect; + textRect.UpperLeftCorner.X = contentWidth + borderWidth; + textRect.UpperLeftCorner.Y = titleHeight + borderWidth; + if ( textHeight < iconHeight ) + textRect.UpperLeftCorner.Y += (iconHeight-textHeight) / 2; + textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + textWidth; + textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + textHeight; + contentWidth += 2*borderWidth + textWidth; + StaticText->setRelativePosition( textRect ); + + // find out button size needs + s32 countButtons = 0; + if (BoxFlags & EMBF_OK) ++countButtons; + if (BoxFlags & EMBF_CANCEL) ++countButtons; + if (BoxFlags & EMBF_YES) ++countButtons; + if (BoxFlags & EMBF_NO) ++countButtons; + s32 buttonBoxWidth = countButtons * buttonWidth + 2 * borderWidth; + if ( countButtons > 1 ) + buttonBoxWidth += (countButtons-1)*buttonDistance; + s32 buttonBoxHeight = buttonHeight + 2 * borderWidth; + + + // calc new message box sizes + core::rect tmp = getRelativePosition(); + s32 msgBoxHeight = titleHeight + contentHeight + buttonBoxHeight; + s32 msgBoxWidth = contentWidth > buttonBoxWidth ? contentWidth : buttonBoxWidth; + + // adjust message box position tmp.UpperLeftCorner.Y = (Parent->getAbsolutePosition().getHeight() - msgBoxHeight) / 2; tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + msgBoxHeight; + tmp.UpperLeftCorner.X = (Parent->getAbsolutePosition().getWidth() - msgBoxWidth) / 2; + tmp.LowerRightCorner.X = tmp.UpperLeftCorner.X + msgBoxWidth; setRelativePosition(tmp); // add buttons - s32 countButtons = 0; - if (Flags & EMBF_OK) ++countButtons; - if (Flags & EMBF_CANCEL) ++countButtons; - if (Flags & EMBF_YES) ++countButtons; - if (Flags & EMBF_NO) ++countButtons; - core::rect btnRect; - btnRect.UpperLeftCorner.Y = pos.Y + dim.Height + buttonHeight / 2; + btnRect.UpperLeftCorner.Y = titleHeight + contentHeight + borderWidth; btnRect.LowerRightCorner.Y = btnRect.UpperLeftCorner.Y + buttonHeight; - btnRect.UpperLeftCorner.X = (AbsoluteClippingRect.getWidth() - - ((buttonWidth + buttonDistance)*countButtons)) / 2; + btnRect.UpperLeftCorner.X = borderWidth; + if ( contentWidth > buttonBoxWidth ) + btnRect.UpperLeftCorner.X += (contentWidth - buttonBoxWidth) / 2; // center buttons btnRect.LowerRightCorner.X = btnRect.UpperLeftCorner.X + buttonWidth; // add/remove ok button - if (Flags & EMBF_OK) + if (BoxFlags & EMBF_OK) { if (!OkButton) { @@ -136,7 +200,7 @@ void CGUIMessageBox::refreshControls() } // add cancel button - if (Flags & EMBF_CANCEL) + if (BoxFlags & EMBF_CANCEL) { if (!CancelButton) { @@ -148,7 +212,6 @@ void CGUIMessageBox::refreshControls() CancelButton->setRelativePosition(btnRect); CancelButton->setText(skin->getDefaultText(EGDT_MSG_BOX_CANCEL)); - CancelButton->grab(); btnRect.LowerRightCorner.X += buttonWidth + buttonDistance; btnRect.UpperLeftCorner.X += buttonWidth + buttonDistance; @@ -166,7 +229,7 @@ void CGUIMessageBox::refreshControls() // add/remove yes button - if (Flags & EMBF_YES) + if (BoxFlags & EMBF_YES) { if (!YesButton) { @@ -193,7 +256,7 @@ void CGUIMessageBox::refreshControls() } // add no button - if (Flags & EMBF_NO) + if (BoxFlags & EMBF_NO) { if (!NoButton) { @@ -242,6 +305,12 @@ CGUIMessageBox::~CGUIMessageBox() if (NoButton) NoButton->drop(); + + if (Icon) + Icon->drop(); + + if ( IconTexture ) + IconTexture->drop(); } @@ -389,10 +458,11 @@ void CGUIMessageBox::serializeAttributes { CGUIWindow::serializeAttributes(out,options); - out->addBool ("OkayButton", (Flags & EMBF_OK) != 0 ); - out->addBool ("CancelButton", (Flags & EMBF_CANCEL)!= 0 ); - out->addBool ("YesButton", (Flags & EMBF_YES) != 0 ); - out->addBool ("NoButton", (Flags & EMBF_NO) != 0 ); + out->addBool ("OkayButton", (BoxFlags & EMBF_OK) != 0 ); + out->addBool ("CancelButton", (BoxFlags & EMBF_CANCEL)!= 0 ); + out->addBool ("YesButton", (BoxFlags & EMBF_YES) != 0 ); + out->addBool ("NoButton", (BoxFlags & EMBF_NO) != 0 ); + out->addTexture ("Texture", IconTexture); out->addString ("MessageText", MessageText.c_str() ); } @@ -400,12 +470,21 @@ void CGUIMessageBox::serializeAttributes //! Reads attributes of the element void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { - Flags = 0; + BoxFlags = 0; - Flags = in->getAttributeAsBool("OkayButton") ? EMBF_OK : 0; - Flags |= in->getAttributeAsBool("CancelButton")? EMBF_CANCEL : 0; - Flags |= in->getAttributeAsBool("YesButton") ? EMBF_YES : 0; - Flags |= in->getAttributeAsBool("NoButton") ? EMBF_NO : 0; + BoxFlags = in->getAttributeAsBool("OkayButton") ? EMBF_OK : 0; + BoxFlags |= in->getAttributeAsBool("CancelButton")? EMBF_CANCEL : 0; + BoxFlags |= in->getAttributeAsBool("YesButton") ? EMBF_YES : 0; + BoxFlags |= in->getAttributeAsBool("NoButton") ? EMBF_NO : 0; + + if ( IconTexture ) + { + IconTexture->drop(); + IconTexture = NULL; + } + IconTexture = in->getAttributeAsTexture("Texture"); + if ( IconTexture ) + IconTexture->grab(); MessageText = in->getAttributeAsStringW("MessageText").c_str(); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMessageBox.h Irrlicht_starsonata/source/Irrlicht/CGUIMessageBox.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIMessageBox.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIMessageBox.h 2008-05-31 04:52:42.000000000 +0200 @@ -13,14 +13,17 @@ namespace irr { namespace gui { + class IGUIImage; + class CGUIMessageBox : public CGUIWindow { public: //! constructor CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption, - const wchar_t* text, s32 flag, - IGUIElement* parent, s32 id, core::rect rectangle); + const wchar_t* text, s32 boxflags, + IGUIElement* parent, s32 id, core::rect rectangle, + video::ITexture* image=0, s32 windowflags=EWF_TITLEBAR); //! destructor ~CGUIMessageBox(); @@ -44,9 +47,12 @@ namespace gui IGUIButton* NoButton; IGUIStaticText* StaticText; - s32 Flags; + s32 BoxFlags; core::stringw MessageText; bool Pressed; + + IGUIImage * Icon; + video::ITexture * IconTexture; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIModalScreen.cpp Irrlicht_starsonata/source/Irrlicht/CGUIModalScreen.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIModalScreen.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIModalScreen.cpp 2008-05-28 20:59:00.000000000 +0200 @@ -37,17 +37,35 @@ CGUIModalScreen::~CGUIModalScreen() //! called if an event happened. bool CGUIModalScreen::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + + if ( !isVisible() ) + return IGUIElement::OnEvent(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)) + if ( event.GUIEvent.Caller != this + && !isMyChild(event.GUIEvent.Caller) + && (!event.GUIEvent.Element + || ( event.GUIEvent.Element->getType() != EGUIET_MODAL_SCREEN + && event.GUIEvent.Element->getType() != EGUIET_MESSAGE_BOX ) + ) + ) Environment->setFocus(this); return false; case EGET_ELEMENT_FOCUS_LOST: - if (!(isMyChild(event.GUIEvent.Element) || event.GUIEvent.Element == this)) + if ( (!isMyChild(event.GUIEvent.Element) + && (!event.GUIEvent.Element + || ( event.GUIEvent.Element->getType() != EGUIET_MODAL_SCREEN + && event.GUIEvent.Element->getType() != EGUIET_MESSAGE_BOX ) + ) + ) + || event.GUIEvent.Element == this) { MouseDownTime = os::Timer::getTime(); return true; @@ -74,6 +92,9 @@ bool CGUIModalScreen::OnEvent(SEvent eve //! draws the element and its children void CGUIModalScreen::draw() { + if ( !isVisible() ) + return; + IGUISkin *skin = Environment->getSkin(); if (!skin) @@ -137,15 +158,15 @@ void CGUIModalScreen::updateAbsolutePosi } //! Writes attributes of the element. -void CGUIModalScreen::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) +void CGUIModalScreen::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) { - // these don't get serialized, their status is added to their children. + IGUIElement::serializeAttributes(out,options); } //! Reads attributes of the element -void CGUIModalScreen::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +void CGUIModalScreen::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) { - // these don't get deserialized. children create them if required + IGUIElement::deserializeAttributes(in, options); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIModalScreen.h Irrlicht_starsonata/source/Irrlicht/CGUIModalScreen.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIModalScreen.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIModalScreen.h 2008-03-23 05:15:34.000000000 +0100 @@ -38,6 +38,33 @@ namespace gui //! Updates the absolute position. virtual void updateAbsolutePosition(); + + //! Starsonata, Micha: added this to get around some trouble with modalscreens + //! Unlike other elements CGUIModalScreen is visible unless all it's children are invisible + //! or any if parents is invisible. + virtual bool isVisible() + { + IGUIElement * parentElement = getParent(); + while ( parentElement ) + { + if ( !parentElement->isVisible() ) + return false; + parentElement = parentElement->getParent(); + } + + bool visible = false; + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + if ( (*it)->isVisible() ) + { + visible = true; + break; + } + } + return visible; + } + //! Writes attributes of the element. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIScrollBar.cpp Irrlicht_starsonata/source/Irrlicht/CGUIScrollBar.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIScrollBar.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIScrollBar.cpp 2008-06-05 06:40:54.000000000 +0200 @@ -21,8 +21,8 @@ CGUIScrollBar::CGUIScrollBar(bool horizo IGUIElement* parent, s32 id, core::rect rectangle, bool noclip) : IGUIScrollBar(environment, parent, id, rectangle), UpButton(0), DownButton(0), - Dragging(false), Horizontal(horizontal), Pos(0), DrawPos(0), - DrawHeight(0), Max(100), SmallStep(10) + Dragging(false), Horizontal(horizontal), Pos(0), DrawCenter(0), + ThumbSize(0), Max(100), SmallStep(10), MinThumbSize(10), PageSize(100) { #ifdef _DEBUG setDebugName("CGUIScrollBar"); @@ -54,6 +54,9 @@ CGUIScrollBar::~CGUIScrollBar() //! called if an event happened. bool CGUIScrollBar::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + switch(event.EventType) { case EET_KEY_INPUT_EVENT: @@ -144,6 +147,18 @@ bool CGUIScrollBar::OnEvent(SEvent event { Dragging = true; Environment->setFocus(this); + + s32 oldPos = Pos; + setPosFromMousePos(event.MouseInput.X, event.MouseInput.Y); + if (Pos != oldPos && Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED; + Parent->OnEvent(event); + } + return true; } else @@ -193,20 +208,21 @@ void CGUIScrollBar::draw() core::rect rect = AbsoluteRect; // draws the background - skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), rect, &AbsoluteClippingRect); + video::SColor backgroundCol = BackgroundOverrideColor.Use ? BackgroundOverrideColor.Color : skin->getColor(EGDC_SCROLLBAR); + skin->draw2DRectangle(this, backgroundCol, rect, &AbsoluteClippingRect); if (Max!=0) { // draw thumb if (Horizontal) { - rect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + DrawPos + RelativeRect.getHeight() - DrawHeight/2; - rect.LowerRightCorner.X = rect.UpperLeftCorner.X + DrawHeight; + rect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + DrawCenter - ThumbSize/2; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + ThumbSize; } else { - rect.UpperLeftCorner.Y = AbsoluteRect.UpperLeftCorner.Y + DrawPos + RelativeRect.getWidth() - DrawHeight/2; - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + DrawHeight; + rect.UpperLeftCorner.Y = AbsoluteRect.UpperLeftCorner.Y + DrawCenter - ThumbSize/2; + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + ThumbSize; } skin->draw3DButtonPaneStandard(this, rect, &AbsoluteClippingRect); @@ -221,38 +237,58 @@ void CGUIScrollBar::updateAbsolutePositi IGUIElement::updateAbsolutePosition(); // todo: properly resize refreshControls(); + refreshThumbPlacing(); +} + +void CGUIScrollBar::setBackgroundOverrideColor(const video::SColor &color) +{ + BackgroundOverrideColor.Use = true; + BackgroundOverrideColor.Color = color; +} +void CGUIScrollBar::clearBackgroundOverrideColor() +{ + BackgroundOverrideColor.Use = false; +} + +void CGUIScrollBar::setPosFromMousePos(s32 x, s32 y) +{ + s32 halfThumb = ThumbSize/2; if (Horizontal) { - f32 f = (RelativeRect.getWidth() - ((f32)RelativeRect.getHeight()*3.0f)) / (f32)Max; - DrawPos = (s32)((Pos * f) + ((f32)RelativeRect.getHeight() * 0.5f)); - DrawHeight = RelativeRect.getHeight(); + f32 f = (RelativeRect.getWidth() - (f32)RelativeRect.getHeight()*2.0f - (f32)ThumbSize) / (f32)Max; + setPos( (s32)((f32)(x-RelativeRect.getHeight()-AbsoluteRect.UpperLeftCorner.X-halfThumb) / f) ); } else { - f32 f = 0.0f; - if (Max != 0) - f = (RelativeRect.getHeight() - ((f32)RelativeRect.getWidth()*3.0f)) / (f32)Max; - - DrawPos = (s32)((Pos * f) + ((f32)RelativeRect.getWidth() * 0.5f)); - DrawHeight = RelativeRect.getWidth(); + f32 f = (RelativeRect.getHeight() - (f32)RelativeRect.getWidth()*2.0f - (f32)ThumbSize) / (f32)Max; + setPos( (s32)((f32)(y-RelativeRect.getWidth()-AbsoluteRect.UpperLeftCorner.Y-halfThumb) / f) ); } } -void CGUIScrollBar::setPosFromMousePos(s32 x, s32 y) +void CGUIScrollBar::refreshThumbPlacing() { + s32 border = 0; + s32 thumbArea = 0; if (Horizontal) { - f32 f = (RelativeRect.getWidth() - ((f32)RelativeRect.getHeight()*3.0f)) / (f32)Max; - setPos((s32)(((f32)(x - AbsoluteRect.UpperLeftCorner.X - RelativeRect.getHeight())) / f)); + border = RelativeRect.getHeight(); + thumbArea = RelativeRect.getWidth() - 2*border; } else { - f32 f = (RelativeRect.getHeight() - ((f32)RelativeRect.getWidth()*3.0f)) / (f32)Max; - setPos((s32)(((f32)y - AbsoluteRect.UpperLeftCorner.Y - RelativeRect.getWidth()) / f)); + border = RelativeRect.getWidth(); + thumbArea = RelativeRect.getHeight() - 2*border; } -} + ThumbSize = Max && PageSize < Max ? s32(f32(PageSize*thumbArea)/f32(Max)) : thumbArea; + if ( ThumbSize < MinThumbSize ) + ThumbSize = MinThumbSize; + if ( ThumbSize > thumbArea ) + ThumbSize = thumbArea; + f32 f = Max ? (f32)(thumbArea-ThumbSize) / (f32)Max : 0.f; + DrawCenter = (s32)core::round( (Pos * f) + ((f32)ThumbSize * 0.5f) )+ border; +} //! sets the position of the scrollbar @@ -264,21 +300,7 @@ void CGUIScrollBar::setPos(s32 pos) if (Pos > Max) Pos = Max; - if (Horizontal) - { - f32 f = (RelativeRect.getWidth() - ((f32)RelativeRect.getHeight()*3.0f)) / (f32)Max; - DrawPos = (s32)((Pos * f) + ((f32)RelativeRect.getHeight() * 0.5f)); - DrawHeight = RelativeRect.getHeight(); - } - else - { - f32 f = 0.0f; - if (Max != 0) - f = (RelativeRect.getHeight() - ((f32)RelativeRect.getWidth()*3.0f)) / (f32)Max; - - DrawPos = (s32)((Pos * f) + ((f32)RelativeRect.getWidth() * 0.5f)); - DrawHeight = RelativeRect.getWidth(); - } + refreshThumbPlacing(); } @@ -340,7 +362,7 @@ void CGUIScrollBar::refreshControls() if (skin) { sprites = skin->getSpriteBank(); - color = skin->getColor(EGDC_WINDOW_SYMBOL); + color = skin->getColor(EGDC_ICON); } if (Horizontal) @@ -356,7 +378,7 @@ void CGUIScrollBar::refreshControls() { UpButton->setSpriteBank(sprites); UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_LEFT), color); - UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_LEFT), color); + UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_LEFT_PRESSED), color); } UpButton->setRelativePosition(core::rect(0,0, h, h)); UpButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); @@ -370,7 +392,7 @@ void CGUIScrollBar::refreshControls() { DownButton->setSpriteBank(sprites); DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_RIGHT), color); - DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_RIGHT), color); + DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_RIGHT_PRESSED), color); } DownButton->setRelativePosition(core::rect(RelativeRect.getWidth()-h, 0, RelativeRect.getWidth(), h)); DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); @@ -388,7 +410,7 @@ void CGUIScrollBar::refreshControls() { UpButton->setSpriteBank(sprites); UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_UP), color); - UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_UP), color); + UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_UP_PRESSED), color); } UpButton->setRelativePosition(core::rect(0,0, w, w)); UpButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); @@ -402,13 +424,24 @@ void CGUIScrollBar::refreshControls() { DownButton->setSpriteBank(sprites); DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), color); - DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), color); + DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN_PRESSED), color); } DownButton->setRelativePosition(core::rect(0,RelativeRect.getHeight()-w, w, RelativeRect.getHeight())); DownButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); } } +void CGUIScrollBar::setPageSize(s32 pageSize) +{ + PageSize = pageSize; + refreshThumbPlacing(); +} + +s32 CGUIScrollBar::getPageSize() +{ + return PageSize; +} + //! Writes attributes of the element. void CGUIScrollBar::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) { @@ -418,6 +451,8 @@ void CGUIScrollBar::serializeAttributes( out->addInt ("Value", Pos); out->addInt ("Max", Max); out->addInt ("SmallStep", SmallStep); + out->addInt ("MinThumbSize", MinThumbSize); + out->addInt ("PageSize", PageSize); } //! Reads attributes of the element @@ -429,9 +464,12 @@ void CGUIScrollBar::deserializeAttribute setMax(in->getAttributeAsInt("Max")); setPos(in->getAttributeAsInt("Value")); setSmallStep(in->getAttributeAsInt("SmallStep")); + MinThumbSize = in->getAttributeAsInt("MinThumbSize"); + PageSize = in->getAttributeAsInt("PageSize"); NoClip = in->getAttributeAsBool("NoClip"); refreshControls(); + refreshThumbPlacing(); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIScrollBar.h Irrlicht_starsonata/source/Irrlicht/CGUIScrollBar.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIScrollBar.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIScrollBar.h 2008-06-05 04:47:46.000000000 +0200 @@ -53,6 +53,22 @@ namespace gui //! updates the rectangle virtual void updateAbsolutePosition(); + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color); + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(); + + // StarSonata, Micha + //! set the page size used for a variable sized thumb + virtual void setPageSize(s32 pageSize); + + // StarSonata, Micha + //! get the page size used for a variable sized thumb + virtual s32 getPageSize(); + //! Writes attributes of the element. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); @@ -63,18 +79,29 @@ namespace gui private: void refreshControls(); + void refreshThumbPlacing(); void setPosFromMousePos(s32 x, s32 y); + struct OverrideColor + { + OverrideColor() : Use(false) {} + bool Use; + video::SColor Color; + }; + IGUIButton* UpButton; IGUIButton* DownButton; bool Dragging; bool Horizontal; s32 Pos; - s32 DrawPos; - s32 DrawHeight; + s32 DrawCenter; + s32 ThumbSize; s32 Max; s32 SmallStep; + s32 MinThumbSize; + s32 PageSize; + OverrideColor BackgroundOverrideColor; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUISkin.cpp Irrlicht_starsonata/source/Irrlicht/CGUISkin.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUISkin.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUISkin.cpp 2008-06-04 06:50:56.000000000 +0200 @@ -46,6 +46,8 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, Colors[EGDC_WINDOW_SYMBOL] = video::SColor(200,10,10,10); Colors[EGDC_ICON] = video::SColor(200,255,255,255); Colors[EGDC_ICON_HIGH_LIGHT] = video::SColor(200,8,36,107); + Colors[EGDC_FLASH_PANE] = video::SColor(200,255,0,0); + Colors[EGDC_FOCUSED_EDITBOX] = video::SColor(101,100,255,255); Sizes[EGDS_SCROLLBAR_SIZE] = 14; Sizes[EGDS_MENU_HEIGHT] = 30; @@ -85,6 +87,8 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, Colors[EGDC_WINDOW_SYMBOL] = 0xd0161616; Colors[EGDC_ICON] = 0xd0161616; Colors[EGDC_ICON_HIGH_LIGHT]= 0xd0606060; + Colors[EGDC_FLASH_PANE] = 0xd0ff0000; + Colors[EGDC_FOCUSED_EDITBOX]= 0xffffffff; Sizes[EGDS_SCROLLBAR_SIZE] = 14; Sizes[EGDS_MENU_HEIGHT] = 48; @@ -132,6 +136,17 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, Icons[EGDI_FILE] = 245; Icons[EGDI_DIRECTORY] = 246; + Icons[EGDI_SORTED_ASCENDING] = 229; + Icons[EGDI_SORTED_DESCENDING] = 236; + Icons[EGDI_CURSOR_UP_PRESSED] = 229; + Icons[EGDI_CURSOR_DOWN_PRESSED] = 230; + Icons[EGDI_CURSOR_LEFT_PRESSED] = 231; + Icons[EGDI_CURSOR_RIGHT_PRESSED] = 232; + Icons[EGDI_DROP_DOWN_PRESSED] = 234; + Icons[EGDI_TAB_ARROW_LEFT] = 231; + Icons[EGDI_TAB_ARROW_LEFT_PRESSED] = 231; + Icons[EGDI_TAB_ARROW_RIGHT] = 232; + Icons[EGDI_TAB_ARROW_RIGHT_PRESSED] = 232; for (u32 i=0; i& r, - const core::rect* clip) + const core::rect* clip, + u32 flashFrequency, u32 flashTime ) { if (!Driver) return; @@ -297,12 +313,26 @@ void CGUISkin::draw3DButtonPaneStandard( if (!UseGradient) { - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + video::SColor col( getColor(EGDC_3D_FACE) ); + if ( flashFrequency ) + { + flashTime = (flashTime%flashFrequency)*2; + f32 d = flashTime <= flashFrequency ? (f32)flashTime / (f32)flashFrequency : 1.f - ((f32)(flashTime-flashFrequency) / (f32)flashFrequency); + col = col.getInterpolated(getColor(EGDC_FLASH_PANE), d); + } + Driver->draw2DRectangle(col, rect, clip); } else { video::SColor c1 = getColor(EGDC_3D_FACE); video::SColor c2 = c1.getInterpolated(getColor(EGDC_3D_DARK_SHADOW), 0.4f); + if ( flashFrequency ) + { + flashTime = (flashTime%flashFrequency)*2; + f32 d = flashTime <= flashFrequency ? (f32)flashTime / (f32)flashFrequency : 1.f - ((f32)(flashTime-flashFrequency) / (f32)flashFrequency); + c1 = c1.getInterpolated(getColor(EGDC_FLASH_PANE), d); + c2 = c2.getInterpolated(getColor(EGDC_FLASH_PANE), d); + } Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); } } @@ -319,7 +349,8 @@ is usually not used by ISkin, but can be implementations to find out how to draw the part exactly. */ void CGUISkin::draw3DButtonPanePressed(IGUIElement* element, const core::rect& r, - const core::rect* clip) + const core::rect* clip, + u32 flashFrequency, u32 flashTime) { if (!Driver) return; @@ -340,12 +371,26 @@ void CGUISkin::draw3DButtonPanePressed(I if (!UseGradient) { - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + video::SColor col( getColor(EGDC_3D_FACE) ); + if ( flashFrequency ) + { + flashTime = (flashTime%flashFrequency)*2; + f32 d = flashTime <= flashFrequency ? (f32)flashTime / (f32)flashFrequency : 1.f - ((f32)(flashTime-flashFrequency) / (f32)flashFrequency); + col = col.getInterpolated(getColor(EGDC_FLASH_PANE), d); + } + Driver->draw2DRectangle(col, rect, clip); } else { video::SColor c1 = getColor(EGDC_3D_FACE); video::SColor c2 = c1.getInterpolated(getColor(EGDC_3D_DARK_SHADOW), 0.4f); + if ( flashFrequency ) + { + flashTime = (flashTime%flashFrequency)*2; + f32 d = flashTime <= flashFrequency ? (f32)flashTime / (f32)flashFrequency : 1.f - ((f32)(flashTime-flashFrequency) / (f32)flashFrequency); + c1 = c1.getInterpolated(getColor(EGDC_FLASH_PANE), d); + c2 = c2.getInterpolated(getColor(EGDC_FLASH_PANE), d); + } Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); } } @@ -660,13 +705,15 @@ implementations to find out how to draw \param rect: Defining area where to draw. \param clip: Clip area. */ void CGUISkin::draw3DTabButton(IGUIElement* element, bool active, - const core::rect& frameRect, const core::rect* clip) + const core::rect& frameRect, const core::rect* clip, EGUI_VERTICAL_ALIGNMENT alignment) { if (!Driver) return; core::rect tr = frameRect; + if ( alignment == EGVA_TOP ) + { tr.LowerRightCorner.X -= 2; tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1; tr.UpperLeftCorner.X += 1; @@ -694,6 +741,39 @@ void CGUISkin::draw3DTabButton(IGUIEleme tr.UpperLeftCorner.X += 1; tr.UpperLeftCorner.Y += 1; Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); + } + else + { + tr.LowerRightCorner.X -= 2; + tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; + tr.UpperLeftCorner.X += 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); + + // draw left highlight + tr = frameRect; + tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; + tr.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); + + // draw grey background + tr = frameRect; + tr.UpperLeftCorner.X += 1; + tr.UpperLeftCorner.Y -= 1; + tr.LowerRightCorner.X -= 2; + tr.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); + + // draw right middle gray shadow + tr.LowerRightCorner.X += 1; + tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1; + //tr.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); + + tr.LowerRightCorner.X += 1; + tr.UpperLeftCorner.X += 1; + tr.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); + } } @@ -706,18 +786,23 @@ implementations to find out how to draw \param rect: Defining area where to draw. \param clip: Clip area. */ void CGUISkin::draw3DTabBody(IGUIElement* element, bool border, bool background, - const core::rect& rect, const core::rect* clip) + const core::rect& rect, const core::rect* clip, s32 tabHeight, EGUI_VERTICAL_ALIGNMENT alignment) { if (!Driver) return; core::rect tr = rect; + if ( tabHeight == -1 ) + tabHeight = getSize(gui::EGDS_BUTTON_HEIGHT); + // draw border. if (border) { + if ( alignment == EGVA_TOP ) + { // draw left hightlight - tr.UpperLeftCorner.Y += getSize(gui::EGDS_BUTTON_HEIGHT) + 2; + tr.UpperLeftCorner.Y += tabHeight + 2; tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); @@ -731,14 +816,44 @@ void CGUISkin::draw3DTabBody(IGUIElement tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); } + else + { + // draw left hightlight + tr.LowerRightCorner.Y -= tabHeight + 2; + tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); + + // draw right shadow + tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; + tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); + + // draw lower shadow + tr = rect; + tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); + } + } if (background) { + if ( alignment == EGVA_TOP ) + { tr = rect; - tr.UpperLeftCorner.Y += getSize(gui::EGDS_BUTTON_HEIGHT) + 2; + tr.UpperLeftCorner.Y += tabHeight + 2; tr.LowerRightCorner.X -= 1; tr.UpperLeftCorner.X += 1; tr.LowerRightCorner.Y -= 1; + } + else + { + tr = rect; + tr.UpperLeftCorner.X += 1; + tr.UpperLeftCorner.Y -= 1; + tr.LowerRightCorner.X -= 1; + tr.LowerRightCorner.Y -= tabHeight + 2; + //tr.UpperLeftCorner.X += 1; + } if (!UseGradient) Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUISkin.h Irrlicht_starsonata/source/Irrlicht/CGUISkin.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUISkin.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUISkin.h 2008-05-23 00:58:52.000000000 +0200 @@ -80,9 +80,15 @@ namespace gui \param element: Pointer to the element which whiches to draw this. This parameter is usually not used by ISkin, but can be used for example by more complex implementations to find out how to draw the part exactly. */ + // Starsonata, Micha: added flashing + //! /param flashFrequency: if not zero then use flashing with the frequency set here + //! /param u32 flashTime: when flashFrequency is not zero then this is value controls the flashing. + // The value should be between 0 and flashFrequency, but will be clipped modulated otherwise also. virtual void draw3DButtonPaneStandard(IGUIElement* element, const core::rect& rect, - const core::rect* clip=0); + const core::rect* clip=0, + u32 flashFrequency=0, u32 flashTime=0 ); + //! draws a pressed 3d button pane /** Used for drawing for example buttons in pressed state. @@ -93,9 +99,14 @@ namespace gui \param element: Pointer to the element which whiches to draw this. This parameter is usually not used by ISkin, but can be used for example by more complex implementations to find out how to draw the part exactly. */ + // Starsonata, Micha: added flashing + //! /param flashFrequency: if not zero then use flashing with the frequency set here + //! /param u32 flashTime: when flashFrequency is not zero then this is value controls the flashing. + // The value should be between 0 and flashFrequency, but will be clipped modulated otherwise also. virtual void draw3DButtonPanePressed(IGUIElement* element, const core::rect& rect, - const core::rect* clip=0); + const core::rect* clip=0, + u32 flashFrequency=0, u32 flashTime=0 ); //! draws a sunken 3d pane /** Used for drawing the background of edit, combo or check boxes. @@ -161,7 +172,8 @@ namespace gui \param clip: Clip area. */ virtual void draw3DTabButton(IGUIElement* element, bool active, const core::rect& rect, - const core::rect* clip=0); + const core::rect* clip=0, + EGUI_VERTICAL_ALIGNMENT alignment=EGVA_TOP); //! draws a tab control body /** \param element: Pointer to the element which whiches to draw this. This parameter @@ -170,10 +182,13 @@ namespace gui \param border: Specifies if the border should be drawn. \param background: Specifies if the background should be drawn. \param rect: Defining area where to draw. - \param clip: Clip area. */ + \param clip: Clip area. + \param tabHeight: Defines the height of the tabs.*/ virtual void draw3DTabBody(IGUIElement* element, bool border, bool background, const core::rect& rect, - const core::rect* clip=0); + const core::rect* clip=0, + s32 tabHeight=-1, + EGUI_VERTICAL_ALIGNMENT alignment=EGVA_TOP); //! draws an icon, usually from the skin's sprite bank /** \param parent: Pointer to the element which wishes to draw this icon. diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUISpinBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUISpinBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUISpinBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUISpinBox.cpp 2008-03-19 17:57:54.000000000 +0100 @@ -65,7 +65,7 @@ CGUISpinBox::CGUISpinBox(const wchar_t* } core::rect rectEdit(0, 0, rectangle.getWidth() - ButtonWidth - 1, rectangle.getHeight()); - EditBox = Environment->addEditBox(text, rectEdit, true, this, -1); + EditBox = Environment->addEditBox(text, rectEdit, true, false, this, -1); EditBox->grab(); EditBox->setSubElement(true); EditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); @@ -149,6 +149,9 @@ void CGUISpinBox::setDecimalPlaces(s32 p bool CGUISpinBox::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + bool changeEvent = false; switch(event.EventType) { diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUISpriteBank.cpp Irrlicht_starsonata/source/Irrlicht/CGUISpriteBank.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUISpriteBank.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUISpriteBank.cpp 2008-05-07 01:41:04.000000000 +0200 @@ -32,6 +32,42 @@ CGUISpriteBank::~CGUISpriteBank() Driver->drop(); } +//! clear everything +void CGUISpriteBank::clear() +{ + // drop textures + for (u32 i=0; idrop(); + Textures.clear(); + Sprites.clear(); + Rectangles.clear(); +} + +s32 CGUISpriteBank::addTextureAsSprite(video::ITexture* texture) +{ + if ( !texture ) + return -1; + + addTexture(texture); + u32 textureIndex = getTextureCount() - 1; + + u32 rectangleIndex = Rectangles.size(); + Rectangles.push_back( core::rect(0,0, texture->getOriginalSize().Width, texture->getOriginalSize().Height) ); + + SGUISprite sprite; + sprite.frameTime = 0; + + SGUISpriteFrame frame; + frame.textureNumber = textureIndex; + frame.rectNumber = rectangleIndex; + sprite.Frames.push_back( frame ); + + Sprites.push_back( sprite ); + + return Sprites.size() - 1; +} + core::array< core::rect >& CGUISpriteBank::getPositions() { return Rectangles; @@ -94,7 +130,7 @@ void CGUISpriteBank::draw2DSprite(u32 in if (loop) frame = f % Sprites[index].Frames.size(); else - frame = (f >= Sprites[index].Frames.size()) ? Sprites[index].Frames.size() : f; + frame = (f >= Sprites[index].Frames.size()) ? Sprites[index].Frames.size()-1 : f; } video::ITexture* tex = Textures[Sprites[index].Frames[frame].textureNumber]; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUISpriteBank.h Irrlicht_starsonata/source/Irrlicht/CGUISpriteBank.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUISpriteBank.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUISpriteBank.h 2008-04-11 11:40:28.000000000 +0200 @@ -26,6 +26,14 @@ public: CGUISpriteBank(IGUIEnvironment* env); virtual ~CGUISpriteBank(); + //! clears sprites, rectangles and textures + virtual void clear(); + + //! Use the whole texture as one non-animated sprite + //! The texture and the corresponding rectangle and sprite will all be added to the end of each array. + //! returns the index of the sprite or -1 on failure + virtual s32 addTextureAsSprite(video::ITexture* texture); + virtual core::array< core::rect >& getPositions(); virtual core::array< SGUISprite >& getSprites(); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIStaticText.cpp Irrlicht_starsonata/source/Irrlicht/CGUIStaticText.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIStaticText.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIStaticText.cpp 2008-06-03 08:16:18.000000000 +0200 @@ -22,18 +22,16 @@ CGUIStaticText::CGUIStaticText(const wch bool background) : IGUIStaticText(environment, parent, id, rectangle), Border(border), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT), - OverrideColorEnabled(false), WordWrap(false), Background(background), - OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)), + OverrideColorEnabled(false), OverrideBgColorEnabled(false), + WordWrap(false), Background(background), + ScrolledLines(0), + OverrideColor(video::SColor(101,255,255,255)), OverrideBgColor(video::SColor(101,210,210,210)), OverrideFont(0), LastBreakFont(0) { #ifdef _DEBUG setDebugName("CGUIStaticText"); #endif - Text = text; - if (environment && environment->getSkin()) - { - BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE); - } + setText(text); } @@ -62,7 +60,7 @@ void CGUIStaticText::draw() if (Background) { - driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect); + driver->draw2DRectangle(OverrideBgColorEnabled ? OverrideBgColor : skin->getColor(gui::EGDC_3D_FACE), frameRect, &AbsoluteClippingRect); } // draw the border @@ -76,9 +74,7 @@ void CGUIStaticText::draw() // draw the text if (Text.size()) { - IGUIFont* font = OverrideFont; - if (!OverrideFont) - font = skin->getFont(); + IGUIFont* font = getCurrentFont(); if (font) { @@ -95,6 +91,12 @@ void CGUIStaticText::draw() font->getDimension(Text.c_str()).Width; } + if ( ScrolledLines ) + { + s32 height = font->getDimension(L"A").Height + font->getKerningHeight(); + frameRect.UpperLeftCorner.Y += ScrolledLines * height; + } + font->draw(Text.c_str(), frameRect, OverrideColorEnabled ? OverrideColor : skin->getColor(IsEnabled ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, &AbsoluteClippingRect); @@ -116,6 +118,8 @@ void CGUIStaticText::draw() r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight; } + r.UpperLeftCorner.Y += ScrolledLines * height; + for (u32 i=0; igetFont(); - + IGUIFont* font = getCurrentFont(); if (!font) return; @@ -276,7 +281,7 @@ void CGUIStaticText::breakText() c = ' '; } - if (c == L' ' || c == 0 || i == (size-1)) + if (c == L' ' || c == 0 /*|| i == (size-1)*/) { if (word.size()) { @@ -325,8 +330,25 @@ void CGUIStaticText::breakText() } } + + s32 whitelgth = font->getDimension(whitespace.c_str()).Width; + s32 worldlgth = font->getDimension(word.c_str()).Width; + + if (length + worldlgth + whitelgth > elWidth) + { + // break to next line + length = worldlgth; + BrokenText.push_back(line); + line = word; + } + else + { + // add word to line line += whitespace; line += word; + length += whitelgth + worldlgth; + } + BrokenText.push_back(line); } @@ -334,6 +356,7 @@ void CGUIStaticText::breakText() //! Sets the new caption of this element. void CGUIStaticText::setText(const wchar_t* text) { + ScrolledLines = 0; IGUIElement::setText(text); breakText(); } @@ -353,10 +376,7 @@ s32 CGUIStaticText::getTextHeight() if (!skin) return 0; - IGUIFont* font = OverrideFont; - if (!OverrideFont) - font = skin->getFont(); - + IGUIFont* font = getCurrentFont(); if (!font) return 0; @@ -371,15 +391,7 @@ s32 CGUIStaticText::getTextHeight() s32 CGUIStaticText::getTextWidth() { - IGUIFont * font = OverrideFont; - - if(!OverrideFont) - { - IGUISkin * skin = Environment->getSkin(); - if(skin) - font = skin->getFont(); - } - + IGUIFont * font = getCurrentFont(); if(!font) return 0; @@ -403,7 +415,37 @@ s32 CGUIStaticText::getTextWidth() } } +// scroll a a multi-line static +// Setting the topline would be: lineScroll( -getFirstVisibleLine() ) +void CGUIStaticText::scrollLines(s32 numberOfLines_) +{ + ScrolledLines += numberOfLines_; +} + +// get the currently top-visible line +s32 CGUIStaticText::getScrolledLines() const +{ + return ScrolledLines; +} + +//! get the number of lines in the static. Will be at least 1. +u32 CGUIStaticText::getLineCount() const +{ + return BrokenText.size(); +} + +// Starsonata, Micha +//! Return the font which is currently used for this element +IGUIFont* CGUIStaticText::getCurrentFont() +{ + if ( OverrideFont ) + return OverrideFont; + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return NULL; + return skin->getFont(); +} //! Writes attributes of the element. //! Implement this to expose the attributes of your element for @@ -413,14 +455,18 @@ void CGUIStaticText::serializeAttributes IGUIStaticText::serializeAttributes(out,options); out->addBool ("Border", Border); - out->addBool ("OverrideColorEnabled", OverrideColorEnabled); out->addBool ("WordWrap", WordWrap); out->addBool ("Background", Background); + out->addBool ("OverrideColorEnabled", OverrideColorEnabled); out->addColor ("OverrideColor", OverrideColor); + out->addBool ("OverrideBgColorEnabled", OverrideBgColorEnabled); + out->addColor ("OverrideBgColor", OverrideBgColor); out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); + out->addInt ("ScrolledLines", ScrolledLines); - // out->addFont ("OverrideFont", OverrideFont); + if ( OverrideFont && OverrideFont->getName().size() ) + out->addString("OverrideFont", OverrideFont->getName().c_str() ); } //! Reads attributes of the element @@ -430,16 +476,22 @@ void CGUIStaticText::deserializeAttribut IGUIStaticText::deserializeAttributes(in,options); Border = in->getAttributeAsBool ("Border"); - OverrideColor = in->getAttributeAsBool("OverrideColor"); - + OverrideColor = in->getAttributeAsColor("OverrideColor"); enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled")); + OverrideBgColor = in->getAttributeAsColor("OverrideBgColor"); + OverrideBgColorEnabled = in->getAttributeAsBool("OverrideBgColorEnabled"); setWordWrap(in->getAttributeAsBool("WordWrap")); Background = in->getAttributeAsBool("Background"); setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames), (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); + ScrolledLines = in->getAttributeAsInt("ScrolledLines"); - // OverrideFont = in->getAttributeAsFont("OverrideFont"); + core::stringc fontName = in->getAttributeAsString("OverrideFont"); + if ( fontName.size() ) + { + setOverrideFont( Environment->getFont(fontName.c_str()) ); + } } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIStaticText.h Irrlicht_starsonata/source/Irrlicht/CGUIStaticText.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIStaticText.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIStaticText.h 2008-06-03 08:02:02.000000000 +0200 @@ -36,8 +36,14 @@ namespace gui //! Sets another color for the text. virtual void setOverrideColor(video::SColor color); - //! Sets another color for the background. - virtual void setBackgroundColor(video::SColor color); + // StarSonata, Micha - this replaces the old setBackgroundColor + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color); + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(); + //! Sets whether to draw the background virtual void setDrawBackground(bool draw); @@ -77,6 +83,25 @@ namespace gui //! Updates the absolute position, splits text if word wrap is enabled virtual void updateAbsolutePosition(); + // Starsonata, Micha + //! scroll a static which has wordwrap enabled + //! numberOfLines_ is added to the currently scrolled lines + //! Resetting to the original state is done with scrollLines(-getScrolledLines()) + //! Scrolled lines are also resetted when the text of the static is changed. + virtual void scrollLines(s32 numberOfLines_); + + // Starsonata, Micha + //! get the amount of lines which are scrolled + virtual s32 getScrolledLines() const; + + // Starsonata, Micha + //! get the number of lines in the static. Will be at least 1. + virtual u32 getLineCount() const; + + // Starsonata, Micha + //! Return the font which is currently used for this element + virtual IGUIFont* getCurrentFont(); + //! Writes attributes of the element. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); @@ -91,10 +116,13 @@ namespace gui bool Border; EGUI_ALIGNMENT HAlign, VAlign; bool OverrideColorEnabled; + bool OverrideBgColorEnabled; bool WordWrap; bool Background; + s32 ScrolledLines; - video::SColor OverrideColor, BGColor; + video::SColor OverrideColor; + video::SColor OverrideBgColor; gui::IGUIFont* OverrideFont; gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated. diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUITabControl.cpp Irrlicht_starsonata/source/Irrlicht/CGUITabControl.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUITabControl.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUITabControl.cpp 2008-06-13 21:15:56.000000000 +0200 @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CGUITabControl.h" +#include "CGUIButton.h" #include "IGUISkin.h" #include "IGUIEnvironment.h" #include "IGUIFont.h" @@ -29,6 +31,15 @@ CGUITab::CGUITab(s32 number, IGUIEnviron #ifdef _DEBUG setDebugName("CGUITab"); #endif + + if ( Environment ) + { + IGUISkin* skin = Environment->getSkin(); + if ( skin ) + { + TextColor = skin->getColor(EGDC_BUTTON_TEXT); + } + } } @@ -54,6 +65,11 @@ void CGUITab::setNumber(s32 n) Number = n; } +//! Called if an event happened. +bool CGUITab::OnEvent(SEvent event) +{ + return IGUIElement::OnEvent(event); +} //! draws the element and its children void CGUITab::draw() @@ -81,6 +97,17 @@ void CGUITab::setBackgroundColor(video:: BackColor = c; } +//! sets the color of the text +void CGUITab::setTextColor(video::SColor c) +{ + TextColor = c; +} + +video::SColor CGUITab::getTextColor() +{ + return TextColor; +} + //! returns true if the tab is drawing its background, false if not bool CGUITab::isDrawingBackground() const { @@ -102,7 +129,7 @@ void CGUITab::serializeAttributes(io::IA out->addInt ("TabNumber", Number); out->addBool ("DrawBackground", DrawBackground); out->addColor ("BackColor", BackColor); - + out->addColor ("TextColor", TextColor); } //! Reads attributes of the element @@ -113,6 +140,7 @@ void CGUITab::deserializeAttributes(io:: setNumber(in->getAttributeAsInt("TabNumber")); setDrawBackground(in->getAttributeAsBool("DrawBackground")); setBackgroundColor(in->getAttributeAsColor("BackColor")); + setTextColor(in->getAttributeAsColor("TextColor")); if (Parent && Parent->getType() == EGUIET_TAB_CONTROL) { @@ -133,11 +161,43 @@ CGUITabControl::CGUITabControl(IGUIEnvir IGUIElement* parent, const core::rect& rectangle, bool fillbackground, bool border, s32 id) : IGUITabControl(environment, parent, id, rectangle), ActiveTab(-1), - Border(border), FillBackground(fillbackground) + Border(border), FillBackground(fillbackground), VerticalAlignment(EGVA_TOP), + UpButton(0), DownButton(0), currentScrollTabIndex(0), ScrollControl(false), TabExtraWidth(20) { #ifdef _DEBUG setDebugName("CGUITabControl"); #endif + + IGUISkin* skin = Environment->getSkin(); + + TabHeight = skin->getSize(gui::EGDS_BUTTON_HEIGHT) + 2; + + + bool NoClip = false; + + s32 h = RelativeRect.getHeight(); + + UpButton = new CGUIButton(Environment, this, -1, core::rect(RelativeRect.getWidth() - (2 * TabHeight) ,2, RelativeRect.getWidth() - TabHeight, TabHeight+2), NoClip); + if (UpButton) + { + UpButton->setSpriteBank(skin->getSpriteBank()); + UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_TAB_ARROW_LEFT), skin->getColor(EGDC_ICON)); + UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_TAB_ARROW_LEFT_PRESSED), skin->getColor(EGDC_ICON)); + UpButton->setVisible( false ); + UpButton->setOverrideFont(Environment->getBuiltInFont()); + } + + DownButton = new CGUIButton(Environment, this, -1, core::rect(RelativeRect.getWidth() - TabHeight, 2, RelativeRect.getWidth(), TabHeight+2), NoClip); + if (DownButton) + { + DownButton->setSpriteBank(skin->getSpriteBank()); + DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_TAB_ARROW_RIGHT), skin->getColor(EGDC_ICON)); + DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_TAB_ARROW_RIGHT_PRESSED), skin->getColor(EGDC_ICON)); + DownButton->setVisible( false ); + DownButton->setOverrideFont(Environment->getBuiltInFont()); + } + + TabMaxWidth = 2 * TabHeight; } @@ -145,9 +205,16 @@ CGUITabControl::CGUITabControl(IGUIEnvir //! destructor CGUITabControl::~CGUITabControl() { + clearTabs(); for (s32 i=0; i<(s32)Tabs.size(); ++i) if (Tabs[i]) Tabs[i]->drop(); + + if (UpButton) + UpButton->drop(); + + if (DownButton) + DownButton->drop(); } @@ -158,10 +225,23 @@ IGUITab* CGUITabControl::addTab(const wc if (!skin) return 0; - s32 tabheight = skin->getSize(gui::EGDS_BUTTON_HEIGHT) + 2; - core::rect r(1,tabheight, - AbsoluteRect.getWidth()-1, - AbsoluteRect.getHeight()-1); + core::rect r; + if ( VerticalAlignment == EGVA_TOP ) + { + r.UpperLeftCorner.X = 1; + r.UpperLeftCorner.Y = TabHeight+2; + + r.LowerRightCorner.X = AbsoluteRect.getWidth()-1; + r.LowerRightCorner.Y = AbsoluteRect.getHeight()-1; + } + else + { + r.UpperLeftCorner.X = 1; + r.UpperLeftCorner.Y = 1; + + r.LowerRightCorner.X = AbsoluteRect.getWidth()-1; + r.LowerRightCorner.Y = AbsoluteRect.getHeight()-TabHeight; + } CGUITab* tab = new CGUITab(Tabs.size(), Environment, this, r, id); @@ -173,10 +253,11 @@ IGUITab* CGUITabControl::addTab(const wc if (ActiveTab == -1) { - ActiveTab = 0; - tab->setVisible(true); + setActiveTab(0); } + RecalculateScrollBar(); + return tab; } @@ -233,16 +314,61 @@ IGUITab* CGUITabControl::getTab(s32 idx) return Tabs[idx]; } +void CGUITabControl::clearTabs() +{ + ActiveTab = -1; + for (s32 i=0; i<(s32)Tabs.size(); ++i) + { + if (Tabs[i]) + { + Tabs[i]->drop(); + } + } + Tabs.clear(); + RecalculateScrollBar(); +} + +void CGUITabControl::removeTab(s32 idx) +{ + if ( idx < 0 || idx >= (s32)Tabs.size() ) + return; + Tabs[idx]->drop(); + Tabs.erase(idx); + if ( ActiveTab >= idx ) + { + -- ActiveTab; + setActiveTab(ActiveTab); + } + RecalculateScrollBar(); +} //! called if an event happened. bool CGUITabControl::OnEvent(SEvent event) { if (!IsEnabled) - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); switch(event.EventType) { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case gui::EGET_BUTTON_CLICKED: + if (event.GUIEvent.Caller == UpButton) + { + scrollLeft(); + return true; + } + else if (event.GUIEvent.Caller == DownButton) + { + scrollRight(); + return true; + } + break; + } + break; + case EET_MOUSE_INPUT_EVENT: switch(event.MouseInput.Event) { @@ -257,7 +383,73 @@ bool CGUITabControl::OnEvent(SEvent even break; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); +} + +void CGUITabControl::scrollLeft() +{ + if ( currentScrollTabIndex > 0 ) + --currentScrollTabIndex; +} + +void CGUITabControl::scrollRight() +{ + if ( currentScrollTabIndex < ((s32)Tabs.size() - 1) ) + { + if ( NeedScrollControl( currentScrollTabIndex, true ) ) + ++currentScrollTabIndex; + } +} + +bool CGUITabControl::NeedScrollControl( s32 startIndex, bool withScrollControl ) +{ + if ( startIndex >= (s32)Tabs.size() ) + startIndex -= 1; + + if ( startIndex < 0 ) + startIndex = 0; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return false; + + IGUIFont* font = skin->getFont(); + video::IVideoDriver* driver = Environment->getVideoDriver(); + + core::rect frameRect(AbsoluteRect); + + if (Tabs.empty()) + return false; + + if (!font) + return false; + + s32 pos = frameRect.UpperLeftCorner.X + 2; + + for (s32 i=startIndex; i<(s32)Tabs.size(); ++i) + { + // get Text + const wchar_t* text = 0; + if (Tabs[i]) + text = Tabs[i]->getText(); + + // get text length + s32 len = font->getDimension(text).Width + TabExtraWidth; + + frameRect.LowerRightCorner.X += len; + + frameRect.UpperLeftCorner.X = pos; + frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len; + pos += len; + + if ( withScrollControl && pos > AbsoluteRect.LowerRightCorner.X - TabMaxWidth ) + return true; + + if ( !withScrollControl && pos > AbsoluteRect.LowerRightCorner.X ) + return true; + } + + return false; } void CGUITabControl::selectTab(core::position2d p) @@ -267,22 +459,36 @@ void CGUITabControl::selectTab(core::pos core::rect frameRect(AbsoluteRect); - s32 tabheight = skin->getSize(gui::EGDS_BUTTON_HEIGHT); + if ( VerticalAlignment == EGVA_TOP ) + { frameRect.UpperLeftCorner.Y += 2; - frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + tabheight; + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + TabHeight; + } + else + { + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - TabHeight; + } + s32 pos = frameRect.UpperLeftCorner.X + 2; + s32 rightCornerTabArea = AbsoluteRect.LowerRightCorner.X - TabMaxWidth; - for (s32 i=0; i<(s32)Tabs.size(); ++i) + for (s32 i=currentScrollTabIndex; i<(s32)Tabs.size(); ++i) { // get Text const wchar_t* text = 0; if (Tabs[i]) text = Tabs[i]->getText(); - // get text length - s32 len = 20; - if (font) - len += font->getDimension(text).Width; + // check if we miss the place to draw at least some minimal button + if ( ScrollControl && pos+2 > rightCornerTabArea ) + return; + + // get text length in units + s32 len = font->getDimension(text).Width + TabExtraWidth; + + // check if we can't draw the whole tab + if ( ScrollControl && pos+len > rightCornerTabArea ) + len = rightCornerTabArea - pos; frameRect.UpperLeftCorner.X = pos; frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len; @@ -318,26 +524,58 @@ void CGUITabControl::draw() if (!font) return; - s32 tabheight = skin->getSize(gui::EGDS_BUTTON_HEIGHT); + if ( VerticalAlignment == EGVA_TOP ) + { frameRect.UpperLeftCorner.Y += 2; - frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + tabheight; + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + TabHeight; + } + else + { + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - TabHeight - 1; + frameRect.LowerRightCorner.Y -= 2; + } + core::rect tr; s32 pos = frameRect.UpperLeftCorner.X + 2; + s32 rightCornerTabArea = AbsoluteRect.LowerRightCorner.X - TabMaxWidth; + + bool needLeftScroll = currentScrollTabIndex > 0; + bool needRightScroll = false; // left and right pos of the active tab s32 left = 0; s32 right = 0; - const wchar_t* activetext = 0; + CGUITab *activeTab = 0; + core::stringw activeText; - for (s32 i=0; i<(s32)Tabs.size(); ++i) + for (s32 i=currentScrollTabIndex; i<(s32)Tabs.size(); ++i) { // get Text - const wchar_t* text = 0; + core::stringw text; if (Tabs[i]) text = Tabs[i]->getText(); - // get text length - s32 len = font->getDimension(text).Width + 20; + // check if we miss the place to draw at least some minimal button + if ( ScrollControl && pos+2 > rightCornerTabArea ) + { + needRightScroll = true; + break; + } + + // get text length in units + s32 len = font->getDimension(text.c_str()).Width + TabExtraWidth; + + // check if we can't draw the whole tab + if ( ScrollControl && pos+len > rightCornerTabArea ) + { + len = rightCornerTabArea - pos; + needRightScroll = true; + + s32 charIdx = font->getCharacterFromPos(text.c_str(), len); + if ( charIdx >= 0 ) + text = text.subString(0, charIdx); + } + frameRect.UpperLeftCorner.X = pos; frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len; pos += len; @@ -346,32 +584,35 @@ void CGUITabControl::draw() { left = frameRect.UpperLeftCorner.X; right = frameRect.LowerRightCorner.X; - activetext = text; + activeText = text; + activeTab = Tabs[i]; } else { - skin->draw3DTabButton(this, false, frameRect, &AbsoluteClippingRect); + skin->draw3DTabButton(this, false, frameRect, &AbsoluteClippingRect, VerticalAlignment); // draw text - font->draw(text, frameRect, skin->getColor(EGDC_BUTTON_TEXT), + font->draw(text.c_str(), frameRect, Tabs[i]->getTextColor(), true, true, &AbsoluteClippingRect); } } // draw active tab - if (left != 0 && right != 0) + if (left != 0 && right != 0 && activeTab != 0) + { + // draw upper highlight frame + if ( VerticalAlignment == EGVA_TOP ) { frameRect.UpperLeftCorner.X = left-2; frameRect.LowerRightCorner.X = right+2; frameRect.UpperLeftCorner.Y -= 2; - skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect); + skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment); // draw text - font->draw(activetext, frameRect, skin->getColor(EGDC_BUTTON_TEXT), + font->draw(activeText.c_str(), frameRect, activeTab->getTextColor(), true, true, &AbsoluteClippingRect); - // draw upper highlight frame tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; tr.LowerRightCorner.X = left - 1; tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1; @@ -382,12 +623,141 @@ void CGUITabControl::draw() tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect); } + else + { - skin->draw3DTabBody(this, Border, FillBackground, AbsoluteRect, &AbsoluteClippingRect); + frameRect.UpperLeftCorner.X = left-2; + frameRect.LowerRightCorner.X = right+2; + frameRect.LowerRightCorner.Y += 2; + + skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment); + + // draw text + font->draw(activeText.c_str(), frameRect, activeTab->getTextColor(), + true, true, &AbsoluteClippingRect); + + tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; + tr.LowerRightCorner.X = left - 1; + tr.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect); + + tr.UpperLeftCorner.X = right; + tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect); + } + } + else + { + if ( VerticalAlignment == EGVA_TOP ) + { + tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; + tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; + tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect); + } + else + { + tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; + tr.LowerRightCorner.X = 1000; + tr.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect); + } + } + + skin->draw3DTabBody(this, Border, FillBackground, AbsoluteRect, &AbsoluteClippingRect, TabHeight, VerticalAlignment); + + + // enable scrollcontrols on need + if ( UpButton ) + UpButton->setEnabled(needLeftScroll); + if ( DownButton ) + DownButton->setEnabled(needRightScroll); IGUIElement::draw(); } +//! Set the height of the tabs +void CGUITabControl::setTabHeight( s32 height ) +{ + if ( height < 0 ) + height = 0; + + TabHeight = height; + + TabMaxWidth = 2 * TabHeight; + + RecalculateScrollBar(); +} + +//! Get the height of the tabs +s32 CGUITabControl::getTabHeight() +{ + return TabHeight; +} + +//! Set the extra width added to tabs on each side of the text +void CGUITabControl::setTabExtraWidth( s32 extraWidth ) +{ + if ( extraWidth < 0 ) + extraWidth = 0; + + TabExtraWidth = extraWidth; + + RecalculateScrollBar(); +} + +//! Get the extra width added to tabs on each side of the text +s32 CGUITabControl::getTabExtraWidth() +{ + return TabExtraWidth; +} + +void CGUITabControl::RecalculateScrollBar() +{ + if ( VerticalAlignment == gui::EGVA_TOP ) + { + UpButton->setRelativePosition( core::rect(RelativeRect.getWidth() - (2 * TabHeight) ,2, RelativeRect.getWidth() - TabHeight, TabHeight+2) ); + DownButton->setRelativePosition( core::rect(RelativeRect.getWidth() - TabHeight, 2, RelativeRect.getWidth(), TabHeight+2) ); + } + else + { + UpButton->setRelativePosition( core::rect(RelativeRect.getWidth() - (2 * TabHeight) ,RelativeRect.getHeight() - TabHeight, RelativeRect.getWidth() - TabHeight, RelativeRect.getHeight()-1) ); + DownButton->setRelativePosition( core::rect(RelativeRect.getWidth() - TabHeight, RelativeRect.getHeight() - TabHeight, RelativeRect.getWidth(), RelativeRect.getHeight()-1) ); + } + + ScrollControl = NeedScrollControl(); + + if ( ScrollControl ) + { + UpButton->setVisible( true ); + DownButton->setVisible( true ); + } + else + { + UpButton->setVisible( false ); + DownButton->setVisible( false ); + } + + this->bringToFront( UpButton ); + this->bringToFront( DownButton ); +} + +//! Set the alignment of the tabs +void CGUITabControl::setTabVerticalAlignment( EGUI_VERTICAL_ALIGNMENT alignment ) +{ + VerticalAlignment = alignment; + + RecalculateScrollBar(); +} + +//! Get the alignment of the tabs +EGUI_VERTICAL_ALIGNMENT CGUITabControl::getTabVerticalAlignment() +{ + return VerticalAlignment; +} //! Returns which tab is currently active s32 CGUITabControl::getActiveTab() @@ -412,18 +782,19 @@ bool CGUITabControl::setActiveTab(s32 id bool changed = (ActiveTab != idx); + if (changed) + { + if ( ActiveTab >= 0 && ActiveTab < (s32)Tabs.size() ) + Tabs[ActiveTab]->setVisible(false); + ActiveTab = idx; - for (s32 i=0; i<(s32)Tabs.size(); ++i) - if (Tabs[i]) - Tabs[i]->setVisible( i == ActiveTab ); + Tabs[ActiveTab]->setVisible(true); - if (changed) - { SEvent event; event.EventType = EET_GUI_EVENT; event.GUIEvent.Caller = this; - event.GUIEvent.Element = 0; + event.GUIEvent.Element = Tabs[ActiveTab]; event.GUIEvent.EventType = EGET_TAB_CHANGED; Parent->OnEvent(event); } @@ -457,6 +828,8 @@ void CGUITabControl::removeChild(IGUIEle // remove real element IGUIElement::removeChild(child); + + RecalculateScrollBar(); } @@ -468,7 +841,7 @@ void CGUITabControl::serializeAttributes out->addInt ("ActiveTab", ActiveTab); out->addBool("Border", Border); out->addBool("FillBackground", FillBackground); - + // TODO: new elements missing } //! Reads attributes of the element @@ -476,6 +849,7 @@ void CGUITabControl::deserializeAttribut { Border = in->getAttributeAsBool("Border"); FillBackground = in->getAttributeAsBool("FillBackground"); + // TODO: new elements missing ActiveTab = -1; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUITabControl.h Irrlicht_starsonata/source/Irrlicht/CGUITabControl.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUITabControl.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUITabControl.h 2008-06-13 21:16:24.000000000 +0200 @@ -7,11 +7,14 @@ #include "IGUITabControl.h" #include "irrArray.h" +#include "IGUISkin.h" namespace irr { namespace gui { + class IGUIButton; + // A tab, onto which other gui elements could be added. class CGUITab : public IGUITab { @@ -32,6 +35,9 @@ namespace gui //! Sets the number virtual void setNumber(s32 n); + //! Called if an event happened + virtual bool OnEvent(SEvent event); + //! draws the element and its children virtual void draw(); @@ -47,18 +53,24 @@ namespace gui //! returns the color of the background virtual video::SColor getBackgroundColor() const; + //! sets the color of the text + virtual void setTextColor(video::SColor c); + + //! gets the color of the text + virtual video::SColor getTextColor(); + //! 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); - private: s32 Number; bool DrawBackground; video::SColor BackColor; + video::SColor TextColor; }; @@ -88,6 +100,14 @@ namespace gui //! Returns a tab based on zero based index virtual IGUITab* getTab(s32 idx); + // Micha, Starsonata + //! remove tab for given index + virtual void removeTab(s32 idx); + + // Micha, Starsonata + //! remove all tabs + virtual void clearTabs(); + //! Brings a tab to front. virtual bool setActiveTab(s32 idx); @@ -106,6 +126,24 @@ namespace gui //! Removes a child. virtual void removeChild(IGUIElement* child); + //! Set the height of the tabs + virtual void setTabHeight( s32 height ); + + //! Get the height of the tabs + virtual s32 getTabHeight(); + + //! Set the alignment of the tabs + virtual void setTabVerticalAlignment( gui::EGUI_VERTICAL_ALIGNMENT alignment ); + + //! Get the alignment of the tabs + virtual gui::EGUI_VERTICAL_ALIGNMENT getTabVerticalAlignment(); + + //! Set the extra width added to tabs on each side of the text + virtual void setTabExtraWidth( s32 extraWidth ); + + //! Get the extra width added to tabs on each side of the text + virtual s32 getTabExtraWidth(); + //! Writes attributes of the element. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); @@ -115,11 +153,24 @@ namespace gui private: void selectTab(core::position2d p); + void scrollLeft(); + void scrollRight(); + bool NeedScrollControl( s32 startIndex=0, bool withScrollControl=false ); + + void RecalculateScrollBar(); core::array Tabs; s32 ActiveTab; bool Border; bool FillBackground; + bool ScrollControl; + s32 TabHeight; + gui::EGUI_VERTICAL_ALIGNMENT VerticalAlignment; + IGUIButton* UpButton; + IGUIButton* DownButton; + s32 TabMaxWidth; + s32 currentScrollTabIndex; + s32 TabExtraWidth; }; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUITable.cpp Irrlicht_starsonata/source/Irrlicht/CGUITable.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUITable.cpp 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/source/Irrlicht/CGUITable.cpp 2008-08-20 14:21:24.000000000 +0200 @@ -0,0 +1,1555 @@ +// 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 + +// 07.10.2005 - Multicolor-Listbox added by A. Buschhueter (Acki) +// A_Buschhueter@gmx.de + +#include "CGUITable.h" +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "IGUISpriteBank.h" +#include "CGUIScrollBar.h" +#include "os.h" +#include "profiler.h" +#include "profile_ids.h" + +#define ARROW_PAD 15 + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUITable::CGUITable(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip, + bool drawBack, bool moveOverSelect) +: IGUITable(environment, parent, id, rectangle), Font(0), + VerticalScrollBar(0), HorizontalScrollBar(0), + Clip(clip), DrawBack(drawBack), MoveOverSelect(moveOverSelect), + Selecting(false), CurrentResizedColumn(-1), ResizeStart(0), ResizableColumns(true), + EnsureRowVisibility(-1), UseOverrideBgColor(false), + ItemHeight(0), TotalItemHeight(0), TotalItemWidth(0), Selected(-1), + CellHeightPadding(2), CellWidthPadding(5), ActiveTab(-1), + CurrentOrdering(EGOM_NONE), DrawFlags(EGTDF_ROWS | EGTDF_COLUMNS | EGTDF_ACTIVE_ROW ), + ContinuationWidth(0), IconBank(0) +{ + #ifdef _DEBUG + setDebugName("CGUITable"); + #endif + + VerticalScrollBar = Environment->addScrollBar(false, core::rect(0, 0, 100, 100), this, -1); + if (VerticalScrollBar) + { + VerticalScrollBar->grab(); + VerticalScrollBar->setNotClipped(false); + VerticalScrollBar->setSubElement(true); + } + + HorizontalScrollBar = Environment->addScrollBar(true, core::rect(0, 0, 100, 100), this, -1); + if ( HorizontalScrollBar ) + { + HorizontalScrollBar->grab(); + HorizontalScrollBar->setNotClipped(false); + HorizontalScrollBar->setSubElement(true); + } + + refreshControls(); +} + + +//! destructor +CGUITable::~CGUITable() +{ + if (VerticalScrollBar) + VerticalScrollBar->drop(); + if ( HorizontalScrollBar ) + HorizontalScrollBar->drop(); + + if (IconBank) + IconBank->drop(); + + if (Font) + Font->drop(); +} + + +void CGUITable::addColumn(const wchar_t* caption, s32 columnIndex) +{ + Column tabHeader; + tabHeader.Name = caption; + tabHeader.Width = Font ? Font->getDimension(caption).Width + (CellWidthPadding * 2) + ARROW_PAD : (CellWidthPadding * 2) + ARROW_PAD; + tabHeader.OrderingMode = EGCO_NONE; + + IGUISkin* skin = Environment->getSkin(); + if (skin) + { + tabHeader.TextColor = skin->getColor(EGDC_BUTTON_TEXT); + } + + if ( columnIndex < 0 || columnIndex >= (s32)Columns.size() ) + { + Columns.push_back(tabHeader); + for ( u32 i=0; i < Rows.size(); ++i ) + { + Cell cell; + Rows[i].Items.push_back(cell); + } + } + else + { + Columns.insert(tabHeader, columnIndex); + for ( u32 i=0; i < Rows.size(); ++i ) + { + Cell cell; + Rows[i].Items.insert(cell, columnIndex); + } + } + + if (ActiveTab == -1) + ActiveTab = 0; + + recalculateWidths(); +} + +//! Set the name for the given column. +//! Column must exist, otherwise nothing will happen. +void CGUITable::setColumnName(u32 columnIndex, const wchar_t* name) +{ + if ( columnIndex >= Columns.size() ) + return; + + Columns[columnIndex].Name = name; +} + +//! remove a column from the table +void CGUITable::removeColumn(u32 columnIndex) +{ + if ( columnIndex < Columns.size() ) + { + Columns.erase(columnIndex); + for ( u32 i=0; i < Rows.size(); ++i ) + { + Rows[i].Items.erase(columnIndex); + } + } + if ( (s32)columnIndex <= ActiveTab ) + ActiveTab = Columns.size() ? 0 : -1; + + recalculateWidths(); +} + +s32 CGUITable::getColumnCount() const +{ + return Columns.size(); +} + +u32 CGUITable::getRowCount() const +{ + return Rows.size(); +} + +bool CGUITable::setActiveColumn(s32 idx, bool doOrder ) +{ + if (idx < 0 || idx >= (s32)Columns.size()) + return false; + + bool changed = (ActiveTab != idx); + + ActiveTab = idx; + if ( ActiveTab < 0 ) + return false; + + if ( doOrder ) + { + switch ( Columns[idx].OrderingMode ) + { + case EGCO_NONE: + CurrentOrdering = EGOM_NONE; + break; + + case EGCO_CUSTOM: + CurrentOrdering = EGOM_NONE; + if (Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = EGET_TABLE_HEADER_CHANGED; + Parent->OnEvent(event); + } + + break; + + case EGCO_ASCENDING: + CurrentOrdering = EGOM_ASCENDING; + break; + + case EGCO_DESCENDING: + CurrentOrdering = EGOM_DESCENDING; + break; + + case EGCO_FLIP_ASCENDING_DESCENDING: + CurrentOrdering = EGOM_ASCENDING == CurrentOrdering ? EGOM_DESCENDING : EGOM_ASCENDING; + break; + default: + CurrentOrdering = EGOM_NONE; + } + + orderRows(getActiveColumn(), CurrentOrdering); + } + + if (changed) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = EGET_TABLE_HEADER_CHANGED; + Parent->OnEvent(event); + } + + return true; +} + +s32 CGUITable::getActiveColumn() const +{ + return ActiveTab; +} + +EGUI_ORDERING_MODE CGUITable::getActiveColumnOrdering() const +{ + return CurrentOrdering; +} + +void CGUITable::setColumnWidth(u32 columnIndex, u32 width) +{ + if ( columnIndex < Columns.size() ) + { + const u32 MIN_WIDTH = Font ? Font->getDimension(Columns[columnIndex].Name.c_str() ).Width + (CellWidthPadding * 2) : CellWidthPadding * 2; + if ( width < MIN_WIDTH ) + width = MIN_WIDTH; + + Columns[columnIndex].Width = width; + + for ( u32 i=0; i < Rows.size(); ++i ) + { + breakText( Rows[i].Items[columnIndex].Text, Rows[i].Items[columnIndex].BrokenText, Columns[columnIndex].Width ); + } + } + recalculateWidths(); +} + + +u32 CGUITable::getColumnTextWidth(u32 columnIndex, bool includePadding, bool includeHeader) const +{ + if ( columnIndex < Columns.size() ) + { + u32 largestWidth = 0; + if ( Font ) + { + if ( includeHeader ) + { + largestWidth = Font->getDimension( Columns[columnIndex].Name.c_str() ).Width; + } + + for ( u32 i=0; i < Rows.size(); ++i ) + { + core::dimension2d dim = Font->getDimension( Rows[i].Items[columnIndex].Text.c_str() ); + if ( (u32)dim.Width > largestWidth ) + { + largestWidth = dim.Width; + } + } + } + + if ( includePadding ) + largestWidth += CellWidthPadding * 2; + + return largestWidth; + } + return 0; +} + + +void CGUITable::setResizableColumns(bool resizable) +{ + ResizableColumns = resizable; +} + + +bool CGUITable::hasResizableColumns() const +{ + return ResizableColumns; +} + +void CGUITable::resizeAllColumns(EGUI_TABLE_COLUMN_RESIZE style) +{ + if ( style == ETCR_FIT_TEXTS ) + { + u32 widthSum = 0; + for (u32 i=0;igetSkin(); + if ( VerticalScrollBar && VerticalScrollBar->isVisible() ) + itemClipWith -= skin->getSize(EGDS_SCROLLBAR_SIZE); + + setColumnWidth(idx, core::max_(itemClipWith-widthSum, width) ); + } + } +} + +void CGUITable::addRow(u32 rowIndex) +{ + Row row; + + if ( rowIndex >= Rows.size() ) + Rows.push_back(row); + else + Rows.insert(row, rowIndex); + + for ( u32 i = 0 ; i < Columns.size() ; ++i ) + { + Cell cell; + Rows[rowIndex].Items.push_back(cell); + } + + recalculateHeights(); +} + +void CGUITable::setRowTexts(u32 rowIndex, const irr::core::array &cellTexts ) +{ + if ( rowIndex < Rows.size() ) + { + for ( u32 i = 0 ; i < cellTexts.size() ; ++i ) + { + setCellText(rowIndex, i, cellTexts[i].c_str() ); + } + + recalculateHeights(); + } +} + +//! set some custom data for the given row +//! \param data: custom data pointer +void CGUITable::setRowData(u32 rowIndex, void * data) +{ + if ( rowIndex < Rows.size() ) + { + Rows[rowIndex].Data = data; + } +} + +//! get the custom row data +void* CGUITable::getRowData(u32 rowIndex) const +{ + if ( rowIndex < Rows.size() ) + return Rows[rowIndex].Data; + return NULL; +} + +bool CGUITable::removeRow(u32 rowIndex) +{ + if ( rowIndex < Rows.size() ) + { + Rows.erase( rowIndex ); + + if ( !(Selected < s32(Rows.size())) ) + Selected = Rows.size() - 1; + + recalculateHeights(); + return true; + } + return false; +} + +//! adds an list item, returns id of item +void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Text = text; + breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width ); + + IGUISkin* skin = Environment->getSkin(); + if ( skin ) + Rows[rowIndex].Items[columnIndex].Color = skin->getColor(EGDC_BUTTON_TEXT); + } +} + +void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text, video::SColor color) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Text = text; + breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width ); + Rows[rowIndex].Items[columnIndex].Color = color; + } +} + +void CGUITable::setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Color = color; + } +} + +//! Set the text of all cells in the given row +void CGUITable::setCellColorsInRow(u32 rowIndex, video::SColor color) +{ + if ( rowIndex < Rows.size() ) + { + for ( u32 i=0; i < Columns.size(); ++i ) + { + Rows[rowIndex].Items[i].Color = color; + } + } +} + +void CGUITable::setCellData(u32 rowIndex, u32 columnIndex, void *data) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Data = data; + } +} + +const wchar_t* CGUITable::getCellText(u32 rowIndex, u32 columnIndex ) const +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + return Rows[rowIndex].Items[columnIndex].Text.c_str(); + } + + return 0; +} + +void* CGUITable::getCellData(u32 rowIndex, u32 columnIndex ) const +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + return Rows[rowIndex].Items[columnIndex].Data; + } + + return 0; +} + +void CGUITable::setCellIcon(u32 rowIndex, u32 columnIndex, s32 icon) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Icon = icon; + } +} + +s32 CGUITable::getCellIcon(u32 rowIndex, u32 columnIndex) const +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + return Rows[rowIndex].Items[columnIndex].Icon; + } + return -1; +} + +void CGUITable::setSpriteBank(const c8 *bankName) +{ + IconBankName = core::stringc(bankName); + IGUISpriteBank* bank = IconBankName.size() ? Environment->getSpriteBank(IconBankName.c_str()) : NULL; + if ( bank != IconBank ) + { + if (IconBank) + IconBank->drop(); + IconBank = bank; + if (IconBank) + IconBank->grab(); + } +} + +//! clears the list +void CGUITable::clear() +{ + Selected = -1; + Rows.clear(); + Columns.clear(); + + if (VerticalScrollBar) + VerticalScrollBar->setPos(0); + if ( HorizontalScrollBar ) + HorizontalScrollBar->setPos(0); + + recalculateHeights(); + recalculateWidths(); +} + +void CGUITable::clearRows() +{ + Selected = -1; + Rows.clear(); + + if (VerticalScrollBar) + VerticalScrollBar->setPos(0); + + recalculateHeights(); +} + +s32 CGUITable::getSelected() const +{ + return Selected; +} + +void CGUITable::setSelected(s32 rowIndex, bool triggerEvent) +{ + s32 oldSelected = Selected; + + Selected = rowIndex; + if ( Selected >= (s32)Rows.size() ) + Selected = -1; + + // post the news + if (Parent && triggerEvent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = (Selected != oldSelected) ? EGET_TABLE_CHANGED : EGET_TABLE_SELECTED_AGAIN; + + Parent->OnEvent(event); + } +} + +void CGUITable::ensureRowVisibility(s32 rowIndex) +{ + if ( rowIndex >= (s32)Rows.size() ) + { + rowIndex = (s32)Rows.size()-1; + } + + EnsureRowVisibility = rowIndex; +} + +void CGUITable::recalculateWidths() +{ + TotalItemWidth=0; + for ( u32 i=0; i < Columns.size(); ++i ) + { + TotalItemWidth += Columns[i].Width; + } + checkScrollbars(); +} + +void CGUITable::recalculateHeights() +{ + TotalItemHeight = 0; + IGUISkin* skin = Environment->getSkin(); + if (Font != skin->getFont()) + { + if (Font) + Font->drop(); + + Font = skin->getFont(); + + ItemHeight = 0; + ContinuationWidth = 0; + + if(Font) + { + ItemHeight = Font->getDimension(L"A").Height + (CellHeightPadding * 2); + Font->grab(); + + if ( ContinuationText.size() ) + { + ContinuationWidth = Font->getDimension(ContinuationText.c_str()).Width; + } + } + } + TotalItemHeight = ItemHeight * Rows.size(); // header is not counted, because we only want items + checkScrollbars(); +} + +// automatic enabled/disabling and resizing of scrollbars +void CGUITable::checkScrollbars() +{ + IGUISkin* skin = Environment->getSkin(); + if ( !HorizontalScrollBar || !VerticalScrollBar || !skin) + return; + + s32 scrollBarSize = skin->getSize(EGDS_SCROLLBAR_SIZE); + bool wasHorizontalScrollBarVisible = HorizontalScrollBar->isVisible(); + bool wasVerticalScrollBarVisible = VerticalScrollBar->isVisible(); + HorizontalScrollBar->setVisible(false); + VerticalScrollBar->setVisible(false); + + // CAREFUL: near identical calculations for tableRect and clientClip are also done in draw + // area of table used for drawing without scrollbars + core::rect tableRect(AbsoluteRect); + tableRect.UpperLeftCorner.X += 1; + tableRect.UpperLeftCorner.Y += 1; + s32 headerBottom = getHeaderBottom(); + + // area of for the items (without header and without scrollbars) + core::rect clientClip(tableRect); + clientClip.UpperLeftCorner.Y = headerBottom ; + + // needs horizontal scroll be visible? + if( TotalItemWidth > clientClip.getWidth() ) + { + clientClip.LowerRightCorner.Y -= scrollBarSize; + HorizontalScrollBar->setVisible(true); + HorizontalScrollBar->setMax(TotalItemWidth - clientClip.getWidth()); + s32 pageSize = TotalItemHeight ? core::round32((f32)HorizontalScrollBar->getMax()*((f32)clientClip.getHeight() / (f32)TotalItemWidth)) : 1; + HorizontalScrollBar->setPageSize( pageSize ); + } + + // needs vertical scroll be visible? + if( TotalItemHeight > clientClip.getHeight() ) + { + clientClip.LowerRightCorner.X -= scrollBarSize; + VerticalScrollBar->setVisible(true); + VerticalScrollBar->setMax(TotalItemHeight - clientClip.getHeight()); + s32 pageSize = TotalItemHeight ? core::round32((f32)VerticalScrollBar->getMax()*((f32)clientClip.getHeight() / (f32)TotalItemHeight)) : 1; + VerticalScrollBar->setPageSize(pageSize); + + // check horizontal again because we have now smaller clientClip + if ( !HorizontalScrollBar->isVisible() ) + { + if( TotalItemWidth > clientClip.getWidth() ) + { + clientClip.LowerRightCorner.Y -= scrollBarSize; + HorizontalScrollBar->setVisible(true); + HorizontalScrollBar->setMax(TotalItemWidth - clientClip.getWidth()); + s32 pageSize = TotalItemHeight ? core::round32((f32)HorizontalScrollBar->getMax()*((f32)clientClip.getWidth() / (f32)TotalItemWidth)) : 1; + HorizontalScrollBar->setPageSize( pageSize ); + } + } + } + + // find the correct size for the vertical scrollbar + if ( VerticalScrollBar->isVisible() ) + { + if (!wasVerticalScrollBarVisible ) + VerticalScrollBar->setPos(0); + + if ( HorizontalScrollBar->isVisible() ) + { + VerticalScrollBar->setRelativePosition( + core::rect(RelativeRect.getWidth() - scrollBarSize, 1, + RelativeRect.getWidth()-1, RelativeRect.getHeight()-(1+scrollBarSize) ) ); + } + else + { + VerticalScrollBar->setRelativePosition( + core::rect(RelativeRect.getWidth() - scrollBarSize, 1, + RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) ); + } + } + + // find the correct size for the horizontal scrollbar + if ( HorizontalScrollBar->isVisible() ) + { + if ( !wasHorizontalScrollBarVisible ) + HorizontalScrollBar->setPos(0); + + if ( VerticalScrollBar->isVisible() ) + { + HorizontalScrollBar->setRelativePosition( core::rect(1, RelativeRect.getHeight() - scrollBarSize, RelativeRect.getWidth()-(1+scrollBarSize), RelativeRect.getHeight()-1) ); + } + else + { + HorizontalScrollBar->setRelativePosition( core::rect(1, RelativeRect.getHeight() - scrollBarSize, RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) ); + } + } +} + +void CGUITable::refreshControls() +{ + updateAbsolutePosition(); + + if ( VerticalScrollBar ) + VerticalScrollBar->setVisible(false); + + if ( HorizontalScrollBar ) + HorizontalScrollBar->setVisible(false); + + recalculateHeights(); + recalculateWidths(); +} + + +//! called if an event happened. +bool CGUITable::OnEvent(SEvent event) +{ + if (!IsEnabled) + return IGUIElement::OnEvent(event); + + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case gui::EGET_SCROLL_BAR_CHANGED: + if (event.GUIEvent.Caller == VerticalScrollBar) + { + // current position will get read out in draw + return true; + } + if (event.GUIEvent.Caller == HorizontalScrollBar) + { + // current position will get read out in draw + return true; + } + break; + case gui::EGET_ELEMENT_FOCUS_LOST: + { + CurrentResizedColumn = -1; + Selecting = false; + } + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + { + if ( !IsEnabled ) + return false; + + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + + switch(event.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + VerticalScrollBar->setPos(VerticalScrollBar->getPos() + (s32)event.MouseInput.Wheel*-10); + return true; + + case EMIE_LMOUSE_PRESSED_DOWN: + + if (Environment->hasFocus(this) && + VerticalScrollBar->isVisible() && + VerticalScrollBar->getAbsolutePosition().isPointInside(p) && + VerticalScrollBar->OnEvent(event)) + return true; + + if (Environment->hasFocus(this) && + HorizontalScrollBar->isVisible() && + HorizontalScrollBar->getAbsolutePosition().isPointInside(p) && + HorizontalScrollBar->OnEvent(event)) + return true; + + if ( dragColumnStart( event.MouseInput.X, event.MouseInput.Y ) ) + { + Environment->setFocus(this); + return true; + } + + if ( selectColumnHeader( event.MouseInput.X, event.MouseInput.Y ) ) + { + return true; + } + + Selecting = true; + Environment->setFocus(this); + return true; + + case EMIE_LMOUSE_LEFT_UP: + + CurrentResizedColumn = -1; + Selecting = false; + if (!getAbsolutePosition().isPointInside(p)) + { + Environment->removeFocus(this); + } + + if (Environment->hasFocus(this) && + VerticalScrollBar->isVisible() && + VerticalScrollBar->getAbsolutePosition().isPointInside(p) && + VerticalScrollBar->OnEvent(event)) + { + return true; + } + + if (Environment->hasFocus(this) && + HorizontalScrollBar->isVisible() && + HorizontalScrollBar->getAbsolutePosition().isPointInside(p) && + HorizontalScrollBar->OnEvent(event)) + { + return true; + } + + selectRowByPosY(event.MouseInput.Y, true); + return true; + + case EMIE_LMOUSE_DOUBLE_CLICK: + { + if ( !getAbsolutePosition().isPointInside(p) ) + return false; + + if ( VerticalScrollBar->isVisible() + && VerticalScrollBar->getAbsolutePosition().isPointInside(p) + ) + { + if ( Environment->hasFocus(this) ) + VerticalScrollBar->OnEvent(event); + return true; + } + + if ( HorizontalScrollBar->isVisible() + && HorizontalScrollBar->getAbsolutePosition().isPointInside(p) + ) + { + if ( Environment->hasFocus(this) ) + HorizontalScrollBar->OnEvent(event); + return true; + } + + if (Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = EGET_ELEMENT_DOUBLE_CLICKED; + Parent->OnEvent(event); + } + + return false; + } + + case EMIE_MOUSE_MOVED: + if ( CurrentResizedColumn >= 0 ) + { + if ( dragColumnUpdate(event.MouseInput.X) ) + { + return true; + } + } + if (Selecting || MoveOverSelect) + { + if (getAbsolutePosition().isPointInside(p)) + { + selectRowByPosY(event.MouseInput.Y, true); + return true; + } + } + break; + default: + break; + } + } + break; + default: + break; + } + + return IGUIElement::OnEvent(event); +} + + +void CGUITable::setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode) +{ + if ( columnIndex < Columns.size() ) + Columns[columnIndex].OrderingMode = mode; +} + + +void CGUITable::swapRows(u32 rowIndexA, u32 rowIndexB) +{ + if ( rowIndexA >= Rows.size() ) + return; + + if ( rowIndexB >= Rows.size() ) + return; + + Row swap = Rows[rowIndexA]; + Rows[rowIndexA] = Rows[rowIndexB]; + Rows[rowIndexB] = swap; + + if ( Selected == s32(rowIndexA) ) + Selected = rowIndexB; + else if( Selected == s32(rowIndexB) ) + Selected = rowIndexA; + +} + +s32 CGUITable::findRowIndexByData(void *data) const +{ + for ( u32 i=0; i ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) ) + return false; + + const s32 CLICK_AREA = 3; // to left and right of line which can be dragged + s32 pos = AbsoluteRect.UpperLeftCorner.X+1; + + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + pos -= HorizontalScrollBar->getPos(); + + pos += TotalItemWidth; + + // have to search from the right as otherwise lines could no longer be resized when a column width is 0 + for ( s32 i = (s32)Columns.size()-1; i >= 0 ; --i ) + { + u32 colWidth = Columns[i].Width; + + if ( xpos >= (pos - CLICK_AREA) && xpos < ( pos + CLICK_AREA ) ) + { + CurrentResizedColumn = i; + ResizeStart = xpos; + return true; + } + + pos -= colWidth; + } + + return false; +} + +bool CGUITable::dragColumnUpdate(s32 xpos) +{ + if ( !ResizableColumns || CurrentResizedColumn < 0 || CurrentResizedColumn >= s32(Columns.size()) ) + { + CurrentResizedColumn = -1; + return false; + } + + s32 width = s32(Columns[CurrentResizedColumn].Width) + (xpos-ResizeStart); + if ( width < 0 ) + width = 0; + setColumnWidth(CurrentResizedColumn, u32(width)); + ResizeStart = xpos; + + return false; +} + +bool CGUITable::selectColumnHeader(s32 xpos, s32 ypos) +{ + if( DrawFlags & EGTDF_HIDE_HEADER ) + return false; + + if ( ypos >= getHeaderBottom() ) + return false; + + s32 pos = AbsoluteRect.UpperLeftCorner.X+1; + + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + pos -= HorizontalScrollBar->getPos(); + + for ( u32 i = 0 ; i < Columns.size() ; ++i ) + { + u32 colWidth = Columns[i].Width; + + if ( xpos >= pos && xpos < ( pos + s32(colWidth) ) ) + { + setActiveColumn( i, true ); + + return true; + } + + pos += colWidth; + } + + return false; +} + +void CGUITable::orderRows( s32 (*compareFn)(u32 idx1, u32 idx2, void * data), void * data ) +{ + if ( !compareFn ) + return; + + Row swap; + + for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i ) + { + for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j ) + { + if ( compareFn(j+1, j, data) < 0 ) + { + swap = Rows[j]; + Rows[j] = Rows[j+1]; + Rows[j+1] = swap; + + if ( Selected == j ) + Selected = j+1; + else if( Selected == j+1 ) + Selected = j; + } + } + } +} + +void CGUITable::orderRows( s32 (*compareFn)(void * rowdata1, void * rowdata2, void * customdata), void * customdata ) +{ + if ( !compareFn ) + return; + + CGUITableCompareFunctor myCmp(compareFn, customdata); + + core::heapsort(Rows.pointer(), Rows.size(), myCmp); + Selected = -1; +} + +// This doublicates some code which can be removed if some1 has fun. +// (because the callback orderRows was added later) +void CGUITable::orderRows(s32 columnIndex, EGUI_ORDERING_MODE mode) +{ + Row swap; + + if ( columnIndex == -1 ) + columnIndex = getActiveColumn(); + if ( columnIndex < 0 ) + return; + + if ( mode == EGOM_ASCENDING ) + { + for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i ) + { + for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j ) + { + if ( Rows[j+1].Items[columnIndex].Text < Rows[j].Items[columnIndex].Text ) + { + swap = Rows[j]; + Rows[j] = Rows[j+1]; + Rows[j+1] = swap; + + if ( Selected == j ) + Selected = j+1; + else if( Selected == j+1 ) + Selected = j; + } + } + } + } + else if ( mode == EGOM_DESCENDING ) + { + for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i ) + { + for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j ) + { + if ( Rows[j].Items[columnIndex].Text < Rows[j+1].Items[columnIndex].Text) + { + swap = Rows[j]; + Rows[j] = Rows[j+1]; + Rows[j+1] = swap; + + if ( Selected == j ) + Selected = j+1; + else if( Selected == j+1 ) + Selected = j; + } + } + } + } +} + +//! override the background color of given row +void CGUITable::setRowOverrideBackground(u32 rowIndex, const video::SColor &color) +{ + if ( rowIndex >= Rows.size() ) + return; + + Rows[rowIndex].UseOverrideBackCol = true; + Rows[rowIndex].OverrideBackCol = color; +} + +//! clear override of the background color of given row +void CGUITable::clearRowOverrideBackground(u32 rowIndex) +{ + if ( rowIndex >= Rows.size() ) + return; + Rows[rowIndex].UseOverrideBackCol = false; +} + +s32 CGUITable::getHeaderBottom() +{ + s32 headerBottom = AbsoluteRect.UpperLeftCorner.Y; + if( !(DrawFlags & EGTDF_HIDE_HEADER) ) + headerBottom += ItemHeight; + return headerBottom; +} + +void CGUITable::selectRowByPosY(s32 ypos, bool triggerEvent) +{ + if ( ypos < getHeaderBottom() ) + return; + + if ( ypos >= AbsoluteRect.LowerRightCorner.Y ) + return; + + // find new selected item. + s32 newSelected = (ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + VerticalScrollBar->getPos(); + if( !(DrawFlags & EGTDF_HIDE_HEADER) ) + newSelected -= ItemHeight; + if (ItemHeight!=0) + newSelected /= ItemHeight; + + if (newSelected >= (s32)Rows.size()) + newSelected = -1; + else if (newSelected<0) + newSelected = 0; + + setSelected(newSelected, triggerEvent); +} + + +//! draws the element and its children +void CGUITable::draw() +{ + if (!IsVisible) + return; + + irr::video::IVideoDriver* driver = Environment->getVideoDriver(); + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + if (!Font) + return; + + // CAREFUL: Near identical calculations for tableRect and clientClip are also done in checkScrollbars and selectColumnHeader + // Also selectRowByPosY has some calculations which need to be checked on changes here. + // Area of table used for drawing without scrollbars + core::rect tableRect(AbsoluteRect); + tableRect.UpperLeftCorner.X += 1; + tableRect.UpperLeftCorner.Y += 1; + if ( VerticalScrollBar && VerticalScrollBar->isVisible() ) + tableRect.LowerRightCorner.X -= skin->getSize(EGDS_SCROLLBAR_SIZE); + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + tableRect.LowerRightCorner.Y -= skin->getSize(EGDS_SCROLLBAR_SIZE); + --tableRect.LowerRightCorner.Y; + + s32 headerBottom = getHeaderBottom(); + + // area of for the items (without header and without scrollbars) + core::rect clientClip(tableRect); + clientClip.UpperLeftCorner.Y = headerBottom; + + core::rect* clipRect = 0; + if (Clip) + clipRect = &AbsoluteClippingRect; + + // draw background for whole element + skin->draw3DSunkenPane(this, UseOverrideBgColor ? OverrideBgColor : skin->getColor(EGDC_3D_FACE), true, DrawBack, AbsoluteRect, clipRect); + + // scrolledTableClient is the area where the table items would be if it could be drawn completely + core::rect scrolledTableClient(clientClip); + scrolledTableClient.LowerRightCorner.Y = scrolledTableClient.UpperLeftCorner.Y + TotalItemHeight; + scrolledTableClient.LowerRightCorner.X = scrolledTableClient.UpperLeftCorner.X + TotalItemWidth; + + if ( VerticalScrollBar && VerticalScrollBar->isVisible() ) + { + // if VerticalScrollBar is visible then not all elements do fit and we might have + // to scroll it to the right place + if ( EnsureRowVisibility >= 0 ) + { + core::rect rowRect(scrolledTableClient); + rowRect.UpperLeftCorner.Y += EnsureRowVisibility * ItemHeight - VerticalScrollBar->getPos(); + rowRect.LowerRightCorner.Y = rowRect.UpperLeftCorner.Y + ItemHeight - VerticalScrollBar->getPos(); + + // is the row is completely visible? + if ( rowRect.UpperLeftCorner.Y < clientClip.UpperLeftCorner.Y + || rowRect.LowerRightCorner.Y > clientClip.LowerRightCorner.Y + ) + { + // scroll so that the row is now at the top + VerticalScrollBar->setPos( EnsureRowVisibility * ItemHeight ); + } + } + + scrolledTableClient.UpperLeftCorner.Y -= VerticalScrollBar->getPos(); + scrolledTableClient.LowerRightCorner.Y -= VerticalScrollBar->getPos(); + } + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + { + scrolledTableClient.UpperLeftCorner.X -= HorizontalScrollBar->getPos(); + scrolledTableClient.LowerRightCorner.X -= HorizontalScrollBar->getPos(); + } + EnsureRowVisibility = -1; + + // rowRect is around the scrolled row + core::rect rowRect(scrolledTableClient); + rowRect.LowerRightCorner.Y = rowRect.UpperLeftCorner.Y + ItemHeight; + + u32 pos; + for ( u32 i = 0 ; i < Rows.size() ; ++i ) + { + if (rowRect.LowerRightCorner.Y >= clientClip.UpperLeftCorner.Y && + rowRect.UpperLeftCorner.Y <= clientClip.LowerRightCorner.Y) + { + // draw row seperator + if ( DrawFlags & EGTDF_ROWS ) + { + core::rect lineRect(rowRect); + lineRect.UpperLeftCorner.Y = lineRect.LowerRightCorner.Y - 1; + driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), lineRect, &clientClip); + } + + core::rect textRect(rowRect); + pos = rowRect.UpperLeftCorner.X; + + // draw override background color + if ((s32)i == Selected && DrawFlags & EGTDF_ACTIVE_ROW ) + { + // draw selected row background highlighted + driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), rowRect, &clientClip); + } + else if ( Rows[i].UseOverrideBackCol ) + { + driver->draw2DRectangle(Rows[i].OverrideBackCol, rowRect, &clientClip); + } + + for ( u32 j = 0 ; j < Columns.size() ; ++j ) + { + textRect.UpperLeftCorner.X = pos + CellWidthPadding; + textRect.LowerRightCorner.X = pos + Columns[j].Width - CellWidthPadding; + + // draw icons + if ( Rows[i].Items[j].Icon >= 0 && IconBank) + { + IconBank->draw2DSprite(Rows[i].Items[j].Icon, + textRect.getCenter(), + &clientClip, + video::SColor(255,255,255,255), + /*u32 starttime=*/0, + /*u32 currenttime=*/0, + /*bool loop=*/true, + /*bool center=*/true); + } + + // draw item text + if ((s32)i == Selected) + { + Font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, skin->getColor(IsEnabled ? EGDC_HIGH_LIGHT_TEXT : EGDC_GRAY_TEXT), false, true, &clientClip); + } + else + { + Font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, IsEnabled ? Rows[i].Items[j].Color : skin->getColor(EGDC_GRAY_TEXT), false, true, &clientClip); + } + + pos += Columns[j].Width; + } + } + + rowRect.UpperLeftCorner.Y += ItemHeight; + rowRect.LowerRightCorner.Y += ItemHeight; + } + + core::rect columnSeparator(clientClip); + pos = scrolledTableClient.UpperLeftCorner.X; + + for (u32 i = 0 ; i < Columns.size() ; ++i ) + { + const wchar_t* text = Columns[i].Name.c_str(); + u32 colWidth = Columns[i].Width; + + core::rect columnrect(pos, tableRect.UpperLeftCorner.Y, pos + colWidth, headerBottom); + + // draw column background + skin->draw3DButtonPaneStandard(this, columnrect, &tableRect); + + // draw column seperator + if ( DrawFlags & EGTDF_COLUMNS ) + { + columnSeparator.UpperLeftCorner.X = pos; + columnSeparator.LowerRightCorner.X = pos + 1; + driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), columnSeparator, &tableRect); + } + + if( !(DrawFlags & EGTDF_HIDE_HEADER) ) + { + // draw header column text + columnrect.UpperLeftCorner.X += CellWidthPadding; + Font->draw(text, columnrect, skin->getColor( IsEnabled ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), false, true, &tableRect); + + // draw icon for active column tab + if ( (s32)i == ActiveTab ) + { + if ( CurrentOrdering == EGOM_ASCENDING ) + { + columnrect.UpperLeftCorner.X = columnrect.LowerRightCorner.X - CellWidthPadding - ARROW_PAD / 2 + 2; + columnrect.UpperLeftCorner.Y += 7; + skin->drawIcon(this,EGDI_SORTED_ASCENDING,columnrect.UpperLeftCorner,0,0,false,&tableRect); + } + else + { + columnrect.UpperLeftCorner.X = columnrect.LowerRightCorner.X - CellWidthPadding - ARROW_PAD / 2 + 2; + columnrect.UpperLeftCorner.Y += 7; + skin->drawIcon(this,EGDI_SORTED_DESCENDING,columnrect.UpperLeftCorner,0,0,false,&tableRect); + } + } + } + + pos += colWidth; + } + + // fill up header background up to the right side + core::rect columnrect(pos, tableRect.UpperLeftCorner.Y, tableRect.LowerRightCorner.X , headerBottom); + skin->draw3DButtonPaneStandard(this, columnrect, &tableRect); + + IGUIElement::draw(); +} + +void CGUITable::breakText(const core::stringw &text, core::stringw & brokenText, u32 cellWidth) +{ + if ( !Font ) + return; + + bool useContinuations = false; + u32 maxLength = cellWidth - CellWidthPadding * 2; + if ( ContinuationWidth && maxLength > ContinuationWidth ) + { + maxLength -= ContinuationWidth; + useContinuations = true; + } + s32 index = Font->getCharacterFromPos(text.c_str(), maxLength); + if ( index >= 0 && index < (s32)text.size() ) + { + if ( useContinuations ) + { + // not perfect, but the old solution was just too slow (often freezed for seconds) + brokenText = text.subString(0, index+1) + ContinuationText; + } + else + { + brokenText = text.subString(0, index+1); + } + } + else + { + brokenText = text; + } +} + +// StarSonata, Micha +//! override the background color +void CGUITable::setBackgroundOverrideColor(const video::SColor &color) +{ + UseOverrideBgColor = true; + OverrideBgColor = color; +} + +// StarSonata, Micha +//! clear the background color override +void CGUITable::clearBackgroundOverrideColor() +{ + UseOverrideBgColor = false; +} + +//! Set some flags influencing the layout of the table +void CGUITable::setDrawFlags(s32 flags) +{ + DrawFlags = flags; +} + +//! Get the flags which influence the layout of the table +s32 CGUITable::getDrawFlags() const +{ + return DrawFlags; +} + + +//! Writes attributes of the element. +void CGUITable::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) +{ + IGUITable::serializeAttributes(out, options); + + out->addInt("ColumnCount", Columns.size()); + u32 i; + for (i=0;iaddString(label.c_str(), Columns[i].Name.c_str() ); + label = "Column"; label += i; label += "color"; + out->addColor(label.c_str(), Columns[i].TextColor ); + label = "Column"; label += i; label += "width"; + out->addInt(label.c_str(), Columns[i].Width ); + label = "Column"; label += i; label += "OrderingMode"; + out->addEnum(label.c_str(), Columns[i].OrderingMode, GUIColumnOrderingNames); + } + + out->addInt("RowCount", Rows.size()); + for (i=0;iaddBool(label.c_str(), Rows[i].UseOverrideBackCol); + if ( Rows[i].UseOverrideBackCol ) + { + label = "Row"; label += i; label += "OverrideBackCol"; + out->addColor(label.c_str(), Rows[i].OverrideBackCol ); + } + + label = "Row"; label += i; label += "ItemCount"; + out->addInt(label.c_str(), Rows[i].Items.size()); + + u32 c; + for ( c=0; c < Rows[i].Items.size(); ++c ) + { + label = "Row"; label += i; label += "cell"; label += c; label += "text"; + out->addString(label.c_str(), Rows[i].Items[c].Text.c_str() ); + // core::stringw BrokenText; // can be recalculated + label = "Row"; label += i; label += "cell"; label += c; label += "color"; + out->addColor(label.c_str(), Rows[i].Items[c].Color ); + label = "Row"; label += i; label += "cell"; label += c; label += "icon"; + out->addInt(label.c_str(), Rows[i].Items[c].Icon ); + // void *data; // can't be serialized + } + } + + // s32 ItemHeight; // can be calculated + // TotalItemHeight // calculated + // TotalItemWidth // calculated + // gui::IGUIFont* Font; // font is just the current font from environment + // gui::IGUIScrollBar* VerticalScrollBar; // not serialized + // gui::IGUIScrollBar* HorizontalScrollBar; // not serialized + + out->addBool ("Clip", Clip); + out->addBool ("DrawBack", DrawBack); + out->addBool ("MoveOverSelect", MoveOverSelect); + + // s32 CurrentResizedColumn; // runtime info - depends on user action + out->addBool ("ResizableColumns", ResizableColumns); + + // s32 Selected; // runtime info - depends on user action + out->addInt("CellWidthPadding", CellWidthPadding ); + out->addInt("CellHeightPadding", CellHeightPadding ); + // s32 ActiveTab; // runtime info - depends on user action + // bool Selecting; // runtime info - depends on user action + out->addEnum("CurrentOrdering", CurrentOrdering, GUIOrderingModeNames); + out->addInt("DrawFlags", DrawFlags); + out->addString("IconBankName", IconBankName.c_str() ); + out->addBool ("UseOverrideBgColor", UseOverrideBgColor); + out->addColor ("OverrideBgColor", OverrideBgColor); +} + +//! Reads attributes of the element +void CGUITable::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IGUITable::deserializeAttributes(in, options); + + Columns.clear(); + u32 columnCount = in->getAttributeAsInt("ColumnCount"); + u32 i; + for (i=0;igetAttributeAsString(label.c_str()).c_str()); + label = "Column"; label += i; label += "color"; + column.TextColor = in->getAttributeAsColor(label.c_str()); + label = "Column"; label += i; label += "width"; + column.Width = in->getAttributeAsInt(label.c_str()); + label = "Column"; label += i; label += "OrderingMode"; + column.OrderingMode = (EGUI_COLUMN_ORDERING) in->getAttributeAsEnumeration(label.c_str(), GUIColumnOrderingNames); + + Columns.push_back(column); + } + + Rows.clear(); + u32 rowCount = in->getAttributeAsInt("RowCount"); + for (i=0;igetAttributeAsBool(label.c_str()); + if ( row.UseOverrideBackCol ) + { + label = "Row"; label += i; label += "OverrideBackCol"; + row.OverrideBackCol = in->getAttributeAsColor(label.c_str()); + } + + Rows.push_back(row); + + label = "Row"; label += i; label += "ItemCount"; + u32 itemCount = in->getAttributeAsInt(label.c_str()); + u32 c; + for ( c=0; c < itemCount; ++c ) + { + Cell cell; + + label = "Row"; label += i; label += "cell"; label += c; label += "text"; + cell.Text = core::stringw(in->getAttributeAsString(label.c_str()).c_str()); + breakText( cell.Text, cell.BrokenText, Columns[c].Width ); + label = "Row"; label += i; label += "cell"; label += c; label += "color"; + cell.Color = in->getAttributeAsColor(label.c_str()); + label = "Row"; label += i; label += "cell"; label += c; label += "icon"; + cell.Icon = in->getAttributeAsInt(label.c_str()); + cell.Data = NULL; + + Rows[Rows.size()-1].Items.push_back(cell); + } + } + + ItemHeight = 0; // calculated + TotalItemHeight = 0; // calculated + TotalItemWidth = 0; // calculated + + // force font recalculation + if ( Font ) + { + Font->drop(); + Font = 0; + } + + Clip = in->getAttributeAsBool("Clip"); + DrawBack = in->getAttributeAsBool("DrawBack"); + MoveOverSelect = in->getAttributeAsBool("MoveOverSelect"); + + CurrentResizedColumn = -1; + ResizeStart = 0; + ResizableColumns = in->getAttributeAsBool("ResizableColumns"); + + Selected = -1; + CellWidthPadding = in->getAttributeAsInt("CellWidthPadding"); + CellHeightPadding = in->getAttributeAsInt("CellHeightPadding"); + ActiveTab = -1; + Selecting = false; + + CurrentOrdering = (EGUI_ORDERING_MODE) in->getAttributeAsEnumeration("CurrentOrdering", GUIOrderingModeNames); + DrawFlags = in->getAttributeAsInt("DrawFlags"); + + IconBankName = in->getAttributeAsString("IconBankName"); + setSpriteBank(IconBankName.c_str()); + + UseOverrideBgColor = in->getAttributeAsBool("UseOverrideBgColor"); + OverrideBgColor = in->getAttributeAsColor("OverrideBgColor"); + + refreshControls(); +} + +} // end namespace gui +} // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUITable.h Irrlicht_starsonata/source/Irrlicht/CGUITable.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUITable.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/source/Irrlicht/CGUITable.h 2008-08-20 14:21:36.000000000 +0200 @@ -0,0 +1,327 @@ +// Copyright (C) 2002-2005 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// 07.10.2005 - Multicolor-Listbox addet by A. Buschhueter (Acki) +// A_Buschhueter@gmx.de + +#ifndef __C_GUI_TABLE_BAR_H_INCLUDED__ +#define __C_GUI_TABLE_BAR_H_INCLUDED__ + +#include "IGUITable.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + + class IGUIFont; + class IGUIScrollBar; + + class CGUITable : public IGUITable + { + public: + //! constructor + CGUITable(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip=true, + bool drawBack=false, bool moveOverSelect=true); + + //! destructor + ~CGUITable(); + + //! Adds a column + //! If columnIndex is outside the current range, do push new colum at the end + virtual void addColumn(const wchar_t* name, s32 columnIndex=-1); + + //! Set the name for the given column. + //! Column must exist, otherwise nothing will happen. + virtual void setColumnName(u32 columnIndex, const wchar_t* name); + + //! remove a column from the table + virtual void removeColumn(u32 columnIndex); + + //! Returns the number of columns in the table control + virtual s32 getColumnCount() const; + + //! Makes a column active. This will trigger an ordering process. + /** \param idx: The id of the column to make active. + \return Returns true if successful. */ + virtual bool setActiveColumn(s32 columnIndex, bool doOrder=false); + + //! Returns which header is currently active + virtual s32 getActiveColumn() const; + + //! Returns the ordering used by the currently active column + virtual EGUI_ORDERING_MODE getActiveColumnOrdering() const; + + //! set a column width + virtual void setColumnWidth(u32 columnIndex, u32 width); + + //! Get the size which the widest text within this column would need + //! \param includePadding_: add the usual padding on both sides + //! \param includeHeader_: Also regard the width of the header text + virtual u32 getColumnTextWidth(u32 columnIndex, bool includePadding=true, bool includeHeader=true) const; + + //! columns can be resized by drag 'n drop + virtual void setResizableColumns(bool resizable); + + //! can columns be resized by drag 'n drop? + virtual bool hasResizableColumns() const; + + // micha, starsonata + //! some comfortable resizing of column widths + virtual void resizeAllColumns(EGUI_TABLE_COLUMN_RESIZE style); + + //! This tells the table control which ordering mode should be used when + //! a column header is clicked. + /** \param columnIndex: The index of the column header. + \param state: If true, a EGET_TABLE_HEADER_CHANGED message will be sent and you can order the table data as you whish.*/ + //! \param mode: One of the modes defined in EGUI_COLUMN_ORDERING + virtual void setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode); + + + //! Returns which row is currently selected + virtual s32 getSelected() const; + + //! Select the row or comletely remove selection by using a rowIndex of -1 + //! if you set triggerEvent to true an EGET_TABLE_CHANGED or EGET_TABLE_SELECTED_AGAIN event will get triggered + virtual void setSelected(s32 rowIndex, bool triggerEvent=false); + + //! Select the row by the y coordinate of a mouse position + //! If the mousepos is above the top-row the selection won't be changed + //! If the mousepos is below the guielement rectangle the selection won't be changed + //! If the mousepos is below the bottom row, but within the guielement rectangle then the selection will be set to -1 (no selection) + virtual void selectRowByPosY(s32 ypos, bool triggerEvent=false); + + //! scroll to the row if it's not visible currently + virtual void ensureRowVisibility(s32 rowIndex); + + //! Returns amount of rows in the tabcontrol + virtual u32 getRowCount() const; + + //! adds a row to the table + /* \param rowIndex: zero based index of rows. The row will be inserted at this + position or pushed at the end for indices beyond the current tablesize */ + virtual void addRow(u32 rowIndex); + + //! sets all cell texts in a row (or at least as many as contained in cellTexts) + /* \param rowIndex: zero based index of rows. It must exit or nothing will happen*/ + //! \param cellTexts: contains the text for all the cells in a row. Each string will be filled in one column. + virtual void setRowTexts(u32 rowIndex, const irr::core::array &cellTexts ); + + //! set some custom data for the given row + //! \param data: custom data pointer + virtual void setRowData(u32 rowIndex, void * data); + + //! get the custom row data + virtual void* getRowData(u32 rowIndex) const; + + //! Remove a row from the table + //! returns true on success and false if the index did not exist + virtual bool removeRow(u32 rowIndex); + + //! clear the table rows, but keep the columns intact + virtual void clearRows(); + + //! Swap two row positions. This is useful for a custom ordering algo. + virtual void swapRows(u32 rowIndexA, u32 rowIndexB); + + //! find the index of the row which contains the same custom data value + //! returns -1 when it did not find it + virtual s32 findRowIndexByData(void *data) const; + + //! This tells the table to start ordering all the rows. You + //! need to explicitly tell the table to reorder the rows when + //! a new row is added or the cells data is changed. This makes + //! the system more flexible and doesn't make you pay the cost + //! of ordering when adding a lot of rows. + //! \param columnIndex: When set to -1 the active column is used. + virtual void orderRows(s32 columnIndex=-1, EGUI_ORDERING_MODE mode=EGOM_NONE); + + //! This tells the table to start ordering all the rows with a custom compare function. + //! \param compareFn: The comparison should return negative numbers if idx1 should be above idx2. See example below. + //! \param customdata: Often used to pass the this pointer of class objects + //! Example for compareFn which sort from small to larger numbers from top to bottom (so nothing will change...): + //! static int MyCompare(u32 idx1, u32 idx2, void * data) + //! { return idx1-idx2; } + virtual void orderRows( s32 (*compareFn)(u32 idx1, u32 idx2, void * customdata), void * customdata=NULL ); + + //! This tells the table to start ordering all the rows with a custom compare function which works with the rowdata + //! \param compareFn: The comparison should return negative numbers if rowdata1 should be above rowdata2. + //! \param customdata: Often used to pass the this pointer of class objects + //! Example for compareFn which sort by the pointer value, so that rows with smaller rowdata pointers will be on top. + //! static int MyCompare(void * rowdata1, void * rowdata2, void * customdata) + //! { return rowdata1-rowdata2; } + virtual void orderRows( s32 (*compareFn)(void * rowdata1, void * rowdata2, void * customdata), void * customdata=NULL ); + + //! override the background color of given row + virtual void setRowOverrideBackground(u32 rowIndex, const video::SColor &color); + + //! clear override of the background color of given row + virtual void clearRowOverrideBackground(u32 rowIndex); + + //! Set the text of a cell + virtual void setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text); + + //! Set the text of a cell, and set a color of this cell. + virtual void setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text, video::SColor color); + + //! Set the data of a cell + //! data will not be serialized. + virtual void setCellData(u32 rowIndex, u32 columnIndex, void *data); + + //! Set the color of a cell text + virtual void setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color); + + //! Set the text of all cells in the given row + virtual void setCellColorsInRow(u32 rowIndex, video::SColor color); + + //! Get the text of a cell + virtual const wchar_t* getCellText(u32 rowIndex, u32 columnIndex ) const; + + //! Get the data of a cell + virtual void* getCellData(u32 rowIndex, u32 columnIndex ) const; + + //! \param icon Sprite index of the Icon within the current sprite bank + virtual void setCellIcon(u32 rowIndex, u32 columnIndex, s32 icon); + + //! get the sprite index of the icon in that cell or -1 for no icon + virtual s32 getCellIcon(u32 rowIndex, u32 columnIndex) const; + + //! set the spritebank used for icons + virtual void setSpriteBank(const c8 *bankName); + + //! clears the table, deletes all items in the table + virtual void clear(); + + //! called if an event happened. + virtual bool OnEvent(SEvent event); + + //! draws the element and its children + virtual void draw(); + + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color); + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(); + + //! Set flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual void setDrawFlags(s32 flags); + + //! Get the flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual s32 getDrawFlags() const; + + //! 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. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); + + //! Reads attributes of the object. + //! Implement this to set the attributes of your scene node animator for + //! scripting languages, editors, debuggers or xml deserialization purposes. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); + + protected: + virtual void refreshControls(); + virtual void checkScrollbars(); + s32 getHeaderBottom(); + + private: + + struct Cell + { + Cell() : Icon(-1), Data(0) {} + core::stringw Text; + core::stringw BrokenText; + video::SColor Color; + s32 Icon; + void *Data; + }; + + struct Row + { + Row() : Data(0), UseOverrideBackCol(false) + {} + + core::array Items; + void *Data; + + bool UseOverrideBackCol; + video::SColor OverrideBackCol; + }; + + struct Column + { + Column() : Width(0), OrderingMode(EGCO_NONE) {} + core::stringw Name; + video::SColor TextColor; + u32 Width; + EGUI_COLUMN_ORDERING OrderingMode; + }; + + class CGUITableCompareFunctor + { + public: + CGUITableCompareFunctor( s32 (*compareFn)(void * , void * , void * ), void * data) + : CompareFn(compareFn) + , CustomData(data) + { + } + + bool operator()(const Row& a, const Row& b) + { + return CompareFn( a.Data, b.Data, CustomData ) < 0 ? true : false; + } + + s32 (*CompareFn)(void * , void * , void * ); + void * CustomData; + }; + + void breakText(const core::stringw &text, core::stringw & brokenText, u32 cellWidth); + bool selectColumnHeader(s32 xpos, s32 ypos); + bool dragColumnStart(s32 xpos, s32 ypos); + bool dragColumnUpdate(s32 xpos); + void recalculateHeights(); + void recalculateWidths(); + + core::array< Column > Columns; + core::array< Row > Rows; + gui::IGUIFont* Font; + gui::IGUIScrollBar* VerticalScrollBar; + gui::IGUIScrollBar* HorizontalScrollBar; + bool Clip; + bool DrawBack; + bool MoveOverSelect; + bool Selecting; + s32 CurrentResizedColumn; + s32 ResizeStart; + bool ResizableColumns; + s32 EnsureRowVisibility; // ensure row with given index is visible on next draw + bool UseOverrideBgColor; + video::SColor OverrideBgColor; + + s32 ItemHeight; + s32 TotalItemHeight; + s32 TotalItemWidth; + s32 Selected; + s32 CellHeightPadding; + s32 CellWidthPadding; + s32 ActiveTab; + EGUI_ORDERING_MODE CurrentOrdering; + s32 DrawFlags; + + core::stringw ContinuationText; + u32 ContinuationWidth; + + core::stringc IconBankName; + gui::IGUISpriteBank* IconBank; + }; +} // end namespace gui +} // end namespace irr + +#endif + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIToolBar.cpp Irrlicht_starsonata/source/Irrlicht/CGUIToolBar.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIToolBar.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIToolBar.cpp 2008-03-19 17:57:32.000000000 +0100 @@ -71,6 +71,9 @@ CGUIToolBar::~CGUIToolBar() //! called if an event happened. bool CGUIToolBar::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { @@ -78,7 +81,7 @@ bool CGUIToolBar::OnEvent(SEvent event) return true; } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } //! draws the element and its children diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIWindow.cpp Irrlicht_starsonata/source/Irrlicht/CGUIWindow.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIWindow.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIWindow.cpp 2008-06-07 11:17:58.000000000 +0200 @@ -16,8 +16,17 @@ namespace gui { //! constructor -CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) -: IGUIWindow(environment, parent, id, rectangle), Dragging(false) +CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, s32 flags) +: IGUIWindow(environment, parent, id, rectangle) +, Dragging(false) +, ResizingTop(false), ResizingRight(false), ResizingBottom(false), ResizingLeft(false) +, MouseOnTopBorder(false), MouseOnRightBorder(false), MouseOnBottomBorder(false), MouseOnLeftBorder(false) +, CloseButton(NULL), MinButton(NULL), RestoreButton(NULL) +, Flags(flags) +, ResizeBorderWidth(3) +, IsTopResizable(false), IsRightResizable(false), IsBottomResizable(false), IsLeftResizable(false) +, IsMovable(false), DrawBackground(true) +, BorderStyle(1) { #ifdef _DEBUG setDebugName("CGUIWindow"); @@ -54,7 +63,6 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* RestoreButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, 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); @@ -68,7 +76,6 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* MinButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, 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); @@ -87,6 +94,8 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* setTabGroup(true); setTabStop(true); setTabOrder(-1); + + refreshControls(); } @@ -104,7 +113,23 @@ CGUIWindow::~CGUIWindow() CloseButton->drop(); } +void CGUIWindow::refreshControls() +{ + if ( Flags & EWF_CLOSE ) + CloseButton->setVisible(true); + else + CloseButton->setVisible(false); + + if ( Flags & EWF_MAXIMIZE ) + RestoreButton->setVisible(true); + else + RestoreButton->setVisible(false); + if ( Flags & EWF_MINIMIZE ) + MinButton->setVisible(true); + else + MinButton->setVisible(false); +} //! called if an event happened. bool CGUIWindow::OnEvent(SEvent event) @@ -114,8 +139,11 @@ bool CGUIWindow::OnEvent(SEvent event) case EET_GUI_EVENT: if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) { + if ( event.GUIEvent.Caller == this ) + { Dragging = false; } + } else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED) { @@ -124,20 +152,68 @@ bool CGUIWindow::OnEvent(SEvent event) Parent->bringToFront(this); } } - else - if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) + else if ( event.GUIEvent.EventType == EGET_ELEMENT_LEFT) + { + MouseOnTopBorder = false; + MouseOnRightBorder = false; + MouseOnBottomBorder = false; + MouseOnLeftBorder = false; + } + else if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) { if (event.GUIEvent.Caller == CloseButton) { + if (Parent) + { + // send close event to parent + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_ELEMENT_CLOSED; + + // if the event was not absorbed + if (!Parent->OnEvent(e)) + { + remove(); + } + return true; + } + else + { remove(); return true; } } + } break; case EET_MOUSE_INPUT_EVENT: switch(event.MouseInput.Event) { case EMIE_LMOUSE_PRESSED_DOWN: + + // check for resizing + if ( isTopResizable() ) + { + if ( event.MouseInput.Y < AbsoluteRect.UpperLeftCorner.Y+ResizeBorderWidth ) + ResizingTop = true; + } + if ( isRightResizable() ) + { + if ( event.MouseInput.X > AbsoluteRect.LowerRightCorner.X-ResizeBorderWidth ) + ResizingRight = true; + } + if ( isBottomResizable() ) + { + if ( event.MouseInput.Y > AbsoluteRect.LowerRightCorner.Y-ResizeBorderWidth ) + ResizingBottom = true; + } + if ( isLeftResizable() ) + { + if ( event.MouseInput.X < AbsoluteRect.UpperLeftCorner.X+ResizeBorderWidth ) + ResizingLeft = true; + } + DragStart.X = event.MouseInput.X; DragStart.Y = event.MouseInput.Y; Dragging = true; @@ -150,8 +226,38 @@ bool CGUIWindow::OnEvent(SEvent event) return true; case EMIE_LMOUSE_LEFT_UP: Dragging = false; + ResizingTop = false; + ResizingRight = false; + ResizingBottom = false; + ResizingLeft = false; return true; + + case EMIE_LMOUSE_DOUBLE_CLICK: + { + // check for click on resize area + if ( ( isTopResizable() && event.MouseInput.Y < AbsoluteRect.UpperLeftCorner.Y+ResizeBorderWidth) + || ( isRightResizable() && event.MouseInput.X > AbsoluteRect.LowerRightCorner.X-ResizeBorderWidth ) + || ( isBottomResizable() && event.MouseInput.Y > AbsoluteRect.LowerRightCorner.Y-ResizeBorderWidth ) + || ( isLeftResizable() && event.MouseInput.X < AbsoluteRect.UpperLeftCorner.X+ResizeBorderWidth ) ) + { + // send a sizing event to parent + SEvent eventDoubleClick; + eventDoubleClick.EventType = EET_GUI_EVENT; + eventDoubleClick.GUIEvent.Caller = this; + eventDoubleClick.GUIEvent.Element = 0; + eventDoubleClick.GUIEvent.EventType = EGET_ELEMENT_DOUBLE_CLICKED; + if ( Parent->OnEvent(eventDoubleClick) ) + return true; + } + + return false; + } + case EMIE_MOUSE_MOVED: + MouseOnTopBorder = false; + MouseOnRightBorder = false; + MouseOnBottomBorder = false; + MouseOnLeftBorder = false; if (Dragging) { // gui window should not be dragged outside its parent @@ -163,12 +269,77 @@ bool CGUIWindow::OnEvent(SEvent event) return true; - + if ( !ResizingTop && !ResizingRight && !ResizingBottom && !ResizingLeft ) + { + if ( isMovable() ) + { move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); + } + } + else + { + ResizingRect = getRelativePosition(); + if ( ResizingTop ) + { + ResizingRect.UpperLeftCorner.Y += event.MouseInput.Y - DragStart.Y; + } + if ( ResizingRight ) + { + ResizingRect.LowerRightCorner.X += event.MouseInput.X - DragStart.X; + } + if ( ResizingBottom ) + { + ResizingRect.LowerRightCorner.Y += event.MouseInput.Y - DragStart.Y; + } + if ( ResizingLeft ) + { + ResizingRect.UpperLeftCorner.X += event.MouseInput.X - DragStart.X; + } + // send a sizing event to parent + SEvent eventSizing; + eventSizing.EventType = EET_GUI_EVENT; + eventSizing.GUIEvent.Caller = this; + eventSizing.GUIEvent.Element = 0; + eventSizing.GUIEvent.EventType = EGET_WINDOW_SIZING; + // if the event was not absorbed + if (!Parent->OnEvent(eventSizing)) + { + setRelativePosition(ResizingRect); + } + } + DragStart.X = event.MouseInput.X; DragStart.Y = event.MouseInput.Y; return true; } + else + { + // check if we could resize + if ( isTopResizable() ) + { + if ( event.MouseInput.Y < AbsoluteRect.UpperLeftCorner.Y+ResizeBorderWidth + && event.MouseInput.Y >= AbsoluteRect.UpperLeftCorner.Y ) + MouseOnTopBorder = true; + } + if ( isRightResizable() ) + { + if ( event.MouseInput.X > AbsoluteRect.LowerRightCorner.X-ResizeBorderWidth + && event.MouseInput.X <= AbsoluteRect.LowerRightCorner.X ) + MouseOnRightBorder = true; + } + if ( isBottomResizable() ) + { + if ( event.MouseInput.Y > AbsoluteRect.LowerRightCorner.Y-ResizeBorderWidth + && event.MouseInput.Y <= AbsoluteRect.LowerRightCorner.Y ) + MouseOnBottomBorder = true; + } + if ( isLeftResizable() ) + { + if ( event.MouseInput.X < AbsoluteRect.UpperLeftCorner.X+ResizeBorderWidth + && event.MouseInput.X >= AbsoluteRect.UpperLeftCorner.X ) + MouseOnLeftBorder = true; + } + } break; } } @@ -182,7 +353,10 @@ void CGUIWindow::updateAbsolutePosition( IGUIElement::updateAbsolutePosition(); } - +bool CGUIWindow::hasFlag( EWINDOW_FLAG flag ) +{ + return (Flags & flag) ? true : false; +} //! draws the element and its children void CGUIWindow::draw() @@ -196,8 +370,10 @@ void CGUIWindow::draw() core::rect *cl = &AbsoluteClippingRect; // draw body fast + if ( Flags & EWF_TITLEBAR ) + { rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), - AbsoluteRect, &AbsoluteClippingRect); + rect, &AbsoluteClippingRect); if (Text.size()) { @@ -209,6 +385,40 @@ void CGUIWindow::draw() if (font) font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true, cl); } + } + else + { + rect = skin->draw3DWindowBackground(this, false, skin->getColor(EGDC_ACTIVE_BORDER), + rect, &AbsoluteClippingRect); + } + + // TODO: Drawing resize-borders is just a placeholder for now. + // The typical solution would be to change the cursor, but Irrlicht does not yet support that. + // So for now draw some rectangles there. + if ( isTopResizable() && (ResizingTop || MouseOnTopBorder) ) + { + skin->draw2DRectangle(this, ResizingTop ? skin->getColor(EGDC_ACTIVE_BORDER) : skin->getColor(EGDC_INACTIVE_BORDER), + core::rect(AbsoluteRect.UpperLeftCorner.X, AbsoluteRect.UpperLeftCorner.Y, AbsoluteRect.LowerRightCorner.X, AbsoluteRect.UpperLeftCorner.Y+ResizeBorderWidth), + &AbsoluteClippingRect); + } + if ( isRightResizable() && (ResizingRight || MouseOnRightBorder) ) + { + skin->draw2DRectangle(this, ResizingRight ? skin->getColor(EGDC_ACTIVE_BORDER) : skin->getColor(EGDC_INACTIVE_BORDER), + core::rect(AbsoluteRect.LowerRightCorner.X - ResizeBorderWidth, AbsoluteRect.UpperLeftCorner.Y, AbsoluteRect.LowerRightCorner.X, AbsoluteRect.LowerRightCorner.Y), + &AbsoluteClippingRect); + } + if ( isBottomResizable() && (ResizingBottom || MouseOnBottomBorder) ) + { + skin->draw2DRectangle(this, ResizingBottom ? skin->getColor(EGDC_ACTIVE_BORDER) : skin->getColor(EGDC_INACTIVE_BORDER), + core::rect(AbsoluteRect.UpperLeftCorner.X, AbsoluteRect.LowerRightCorner.Y - ResizeBorderWidth, AbsoluteRect.LowerRightCorner.X, AbsoluteRect.LowerRightCorner.Y), + &AbsoluteClippingRect); + } + if ( isLeftResizable() && (ResizingLeft || MouseOnLeftBorder) ) + { + skin->draw2DRectangle(this, ResizingLeft ? skin->getColor(EGDC_ACTIVE_BORDER) : skin->getColor(EGDC_INACTIVE_BORDER), + core::rect(AbsoluteRect.UpperLeftCorner.X, AbsoluteRect.UpperLeftCorner.Y, AbsoluteRect.UpperLeftCorner.X+ResizeBorderWidth, AbsoluteRect.LowerRightCorner.Y), + &AbsoluteClippingRect); + } IGUIElement::draw(); } @@ -237,6 +447,156 @@ IGUIButton* CGUIWindow::getMaximizeButto return RestoreButton; } +core::rect * CGUIWindow::getSizingRect() +{ + return &ResizingRect; +} + +void CGUIWindow::setTopResizable(bool resizable) +{ + IsTopResizable = resizable; + if ( !IsTopResizable ) + { + ResizingTop = false; + MouseOnTopBorder = false; + } +} + +bool CGUIWindow::isTopResizable() const +{ + return IsTopResizable; +} + +void CGUIWindow::setRightResizable(bool resizable) +{ + IsRightResizable = resizable; + if ( !IsRightResizable ) + { + ResizingRight = false; + MouseOnRightBorder = false; + } +} + +bool CGUIWindow::isRightResizable() const +{ + return IsRightResizable; +} + +void CGUIWindow::setBottomResizable(bool resizable) +{ + IsBottomResizable = resizable; + if ( !IsBottomResizable ) + { + ResizingBottom = false; + MouseOnBottomBorder = false; + } +} + +bool CGUIWindow::isBottomResizable() const +{ + return IsBottomResizable; +} + +void CGUIWindow::setLeftResizable(bool resizable) +{ + IsLeftResizable = resizable; + if ( !IsLeftResizable ) + { + ResizingLeft = false; + MouseOnLeftBorder = false; + } +} + +bool CGUIWindow::isLeftResizable() const +{ + return IsLeftResizable; +} + +void CGUIWindow::setMovable(bool movable) +{ + IsMovable = movable; + + if ( !IsMovable ) + Dragging = false; +} + +bool CGUIWindow::isMovable() const +{ + return IsMovable; +} + +void CGUIWindow::setDrawBackground(bool draw) +{ + DrawBackground = draw; +} + +bool CGUIWindow::getDrawBackground() const +{ + return DrawBackground; +} + +void CGUIWindow::setBorderStyle(u32 style) +{ + BorderStyle = style; +} + +u32 CGUIWindow::getBorderStyle() const +{ + return BorderStyle; +} + +//! Writes attributes of the element. +void CGUIWindow::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) +{ + IGUIWindow::serializeAttributes(out, options); + + //core::position2d DragStart; // runtime info - no need for serialization + //bool Dragging; // runtime info - no need for serialization + //bool ResizingTop; // runtime info - no need for serialization + //bool ResizingRight; // runtime info - no need for serialization + //bool ResizingBottom; // runtime info - no need for serialization + //bool ResizingLeft; // runtime info - no need for serialization + //bool MouseOnTopBorder; // runtime info - no need for serialization + //bool MouseOnRightBorder; // runtime info - no need for serialization + //bool MouseOnBottomBorder; // runtime info - no need for serialization + //bool MouseOnLeftBorder; // runtime info - no need for serialization + + //IGUIButton* CloseButton; // currently those are always at whole lifetime of the object + //IGUIButton* MinButton; // currently those are always at whole lifetime of the object + //IGUIButton* RestoreButton; // currently those are always at whole lifetime of the object + + out->addInt ("Flags", Flags ); + out->addInt ("ResizeBorderWidth", ResizeBorderWidth); + + out->addBool("TopResizable", IsTopResizable); + out->addBool("RightResizable", IsRightResizable); + out->addBool("BottomResizable", IsBottomResizable); + out->addBool("LeftResizable", IsLeftResizable); + out->addBool("Movable", IsMovable); + out->addBool("DrawBackground", DrawBackground); + out->addInt ("BorderStyle", BorderStyle ); +} + +//! Reads attributes of the element +void CGUIWindow::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IGUIWindow::deserializeAttributes(in, options); + + Flags = in->getAttributeAsInt("Flags"); + ResizeBorderWidth = in->getAttributeAsInt("ResizeBorderWidth"); + + setTopResizable( in->getAttributeAsBool("TopResizable") ); + setRightResizable( in->getAttributeAsBool("RightResizable") ); + setBottomResizable( in->getAttributeAsBool("BottomResizable") ); + setLeftResizable( in->getAttributeAsBool("LeftResizable") ); + setMovable( in->getAttributeAsBool("Movable") ); + setDrawBackground( in->getAttributeAsBool("DrawBackground") ); + setBorderStyle( in->getAttributeAsInt("BorderStyle") ); + + refreshControls(); +} + + } // end namespace gui } // end namespace irr diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIWindow.h Irrlicht_starsonata/source/Irrlicht/CGUIWindow.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIWindow.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIWindow.h 2008-05-31 04:53:10.000000000 +0200 @@ -18,7 +18,7 @@ namespace gui public: //! constructor - CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, s32 flags=EWF_CLOSE|EWF_TITLEBAR); //! destructor ~CGUIWindow(); @@ -41,14 +41,68 @@ namespace gui //! Returns pointer to the maximize button virtual IGUIButton* getMaximizeButton(); + //! On EGET_WINDOW_SIZING events you can access and change the sizing rect + virtual core::rect * getSizingRect(); + + //! 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); + + // starsonata, micha + //! return if given flag is set + virtual bool hasFlag( EWINDOW_FLAG flag ); + + // starsonata, micha, bunch of flags which turned out to be useful + virtual void setTopResizable(bool resizable); + virtual bool isTopResizable() const; + virtual void setRightResizable(bool resizable); + virtual bool isRightResizable() const; + virtual void setBottomResizable(bool resizable); + virtual bool isBottomResizable() const; + virtual void setLeftResizable(bool resizable); + virtual bool isLeftResizable() const; + virtual void setMovable(bool movable); + virtual bool isMovable() const; + virtual void setDrawBackground(bool draw); + virtual bool getDrawBackground() const; + + // starsonata, micha + //! define the way the borders should look like + //! It's up to the skin to interpret the style + virtual void setBorderStyle(u32 style); + virtual u32 getBorderStyle() const; + protected: + void refreshControls(); + core::position2d DragStart; bool Dragging; + bool ResizingTop; + bool ResizingRight; + bool ResizingBottom; + bool ResizingLeft; + core::rect ResizingRect; + bool MouseOnTopBorder; + bool MouseOnRightBorder; + bool MouseOnBottomBorder; + bool MouseOnLeftBorder; IGUIButton* CloseButton; IGUIButton* MinButton; IGUIButton* RestoreButton; + + s32 Flags; + s32 ResizeBorderWidth; + bool IsTopResizable; + bool IsRightResizable; + bool IsBottomResizable; + bool IsLeftResizable; + bool IsMovable; + bool DrawBackground; + u32 BorderStyle; }; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CImage.cpp Irrlicht_starsonata/source/Irrlicht/CImage.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CImage.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CImage.cpp 2008-05-08 01:57:18.000000000 +0200 @@ -1267,6 +1267,49 @@ void CImage::drawLine(const core::positi } } +// starsonata, micha, needed this for padding d3d textures +// Not yet much tested. +//! copies this surface into another +// note: slow +void CImage::copyTo(void* target, s32 width, s32 height, ECOLOR_FORMAT format, u32 pitch, const core::position2d& pos) +{ + if (!target || !width || !height) + return; + + const u32 bpp=getBitsPerPixelFromFormat(format)/8; + if (0==pitch) + pitch = width*bpp; + + core::rect sourceRect(0,0, Size.Width, Size.Height); + if ( pos.X < 0 ) + sourceRect.UpperLeftCorner.X -= pos.X; + if ( pos.Y < 0 ) + sourceRect.UpperLeftCorner.Y -= pos.Y; + if ( sourceRect.LowerRightCorner.X + pos.X > width ) + sourceRect.LowerRightCorner.X = width - pos.X; + if ( sourceRect.LowerRightCorner.Y + pos.Y > height ) + sourceRect.LowerRightCorner.Y = height - pos.Y; + + s32 syval=sourceRect.UpperLeftCorner.Y*Pitch; + s32 tyval=pos.Y*pitch; + for (s32 y=sourceRect.UpperLeftCorner.Y; ylock(), targetSize.Width, targetSize.Height, target->getColorFormat()); + target->unlock(); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CImage.h Irrlicht_starsonata/source/Irrlicht/CImage.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CImage.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CImage.h 2008-05-08 00:58:42.000000000 +0200 @@ -99,6 +99,10 @@ public: //! copies this surface into another, scaling it to fit. void copyToScaling(void* target, s32 width, s32 height, ECOLOR_FORMAT format, u32 pitch=0); + // starsonata, micha, needed this for padding d3d textures + //! copies this surface into another + virtual void copyTo(void* target, s32 width, s32 height, ECOLOR_FORMAT format, u32 pitch=0, const core::position2d& pos=core::position2d(0,0)); + //! copies this surface into another, scaling it to fit. void copyToScaling(IImage* target); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceLinux.cpp Irrlicht_starsonata/source/Irrlicht/CIrrDeviceLinux.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceLinux.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CIrrDeviceLinux.cpp 2008-03-23 05:18:48.000000000 +0100 @@ -656,7 +656,21 @@ void CIrrDeviceLinux::createDriver(const } } +//! MICHA: remove all events pending in the message loop +void CIrrDeviceLinux::clearPendingEvents() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (DriverType != video::EDT_NULL) + { + irr::SEvent irrevent; + while (XPending(display) > 0 ) + { + XNextEvent(display, &event); + } + } +#endif //_IRR_COMPILE_WITH_X11_ +} //! runs the device. Returns false if device wants to be deleted bool CIrrDeviceLinux::run() @@ -707,6 +721,8 @@ bool CIrrDeviceLinux::run() irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; irrevent.MouseInput.X = event.xbutton.x; irrevent.MouseInput.Y = event.xbutton.y; + irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0; + irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0; postEventFromUser(irrevent); break; @@ -717,6 +733,8 @@ bool CIrrDeviceLinux::run() irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; irrevent.MouseInput.X = event.xbutton.x; irrevent.MouseInput.Y = event.xbutton.y; + irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0; + irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0; irrevent.MouseInput.Event = irr::EMIE_COUNT; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceLinux.h Irrlicht_starsonata/source/Irrlicht/CIrrDeviceLinux.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceLinux.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CIrrDeviceLinux.h 2007-11-16 01:41:08.000000000 +0100 @@ -80,6 +80,9 @@ namespace irr //! Sets if the window should be resizeable in windowed mode. virtual void setResizeAble(bool resize=false); + //! MICHA: remove all events pending in the message loop + virtual void clearPendingEvents(); + private: //! create the driver diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceStub.cpp Irrlicht_starsonata/source/Irrlicht/CIrrDeviceStub.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceStub.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CIrrDeviceStub.cpp 2008-05-15 04:19:58.000000000 +0200 @@ -12,6 +12,8 @@ #include "CTimer.h" #include "CLogger.h" #include "irrString.h" +#include "profiler.h" +#include "profile_ids.h" namespace irr { @@ -31,6 +33,13 @@ CIrrDeviceStub::CIrrDeviceStub(const cha os::Printer::log(s.c_str(), ELL_INFORMATION); checkVersion(version); + + PROFILE_ADD_GROUP(EPG_IRRLICHT, "Irrlicht"); + PROFILE_ADD(EPD_TESTING1, EPG_IRRLICHT, "TESTING1"); + PROFILE_ADD(EPD_TESTING2, EPG_IRRLICHT, "TESTING2"); + PROFILE_ADD(EPD_TESTING3, EPG_IRRLICHT, "TESTING3"); + PROFILE_ADD(EPD_TESTING4, EPG_IRRLICHT, "TESTING4"); + PROFILE_ADD(EPD_TESTING5, EPG_IRRLICHT, "TESTING5"); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceStub.h Irrlicht_starsonata/source/Irrlicht/CIrrDeviceStub.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceStub.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CIrrDeviceStub.h 2008-02-27 00:15:30.000000000 +0100 @@ -98,6 +98,27 @@ namespace irr //! Returns the operation system opertator object. virtual IOSOperator* getOSOperator(); + //! MICHA: remove all events pending in the message loop + virtual void clearPendingEvents() {} + + // starsonata, micha: + //! minimize the application. Only supported on windows so far. + virtual void minimize() {} + + //! minimize the application. Only supported on windows so far. + virtual void maximize() {} + + //! restore mainwindow to original size. Only supported on windows so far. + virtual void restore() {} + + // starsonata, micha: + //! Check if application is minimized. Only supported on windows so far. + virtual bool isMinimized() { return false; } + + // starsonata, micha: + //! Check if main window is maximized. Only supported on windows so far. + virtual bool isMaximized() { return false; } + protected: void createGUIAndScene(); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceWin32.cpp Irrlicht_starsonata/source/Irrlicht/CIrrDeviceWin32.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceWin32.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CIrrDeviceWin32.cpp 2008-06-24 21:30:22.000000000 +0200 @@ -18,6 +18,7 @@ #include #include "irrlicht.h" +#pragma warning(disable:4800) // 'int' : forcing value to bool 'true' or 'false' (performance warning) namespace irr { @@ -125,6 +126,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT ClientToScreen(hWnd, &p); event.MouseInput.X = LOWORD(lParam) - p.x; event.MouseInput.Y = HIWORD(lParam) - p.y; + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; dev = getDeviceFromHWnd(hWnd); if (dev) @@ -138,6 +141,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); @@ -154,9 +160,93 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + + dev = getDeviceFromHWnd(hWnd); + if (dev) + dev->postEventFromUser(event); + return 0; + + case WM_LBUTTONDBLCLK: + // send the usual click first + ClickCount++; + SetCapture(hWnd); + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + + dev = getDeviceFromHWnd(hWnd); + if (dev) + dev->postEventFromUser(event); + + // send additionally the double click + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = irr::EMIE_LMOUSE_DOUBLE_CLICK; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + + if (dev) + dev->postEventFromUser(event); + return 0; + + case WM_RBUTTONDBLCLK: + // send the usual click first + ClickCount++; + SetCapture(hWnd); + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + + dev = getDeviceFromHWnd(hWnd); + if (dev) + dev->postEventFromUser(event); + + // send additionally the double click + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = irr::EMIE_RMOUSE_DOUBLE_CLICK; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + + if (dev) + dev->postEventFromUser(event); + return 0; + + case WM_MBUTTONDBLCLK: + // send the usual click first + ClickCount++; + SetCapture(hWnd); + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); + + // send additionally the double click + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = irr::EMIE_MMOUSE_DOUBLE_CLICK; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + + if (dev) + dev->postEventFromUser(event); return 0; case WM_RBUTTONDOWN: @@ -166,6 +256,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); @@ -182,6 +275,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); @@ -194,6 +290,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); @@ -210,6 +309,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); @@ -220,6 +322,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT event.MouseInput.Event = irr::EMIE_MOUSE_MOVED; event.MouseInput.X = (short)LOWORD(lParam); event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = LOWORD(wParam) & MK_SHIFT; + event.MouseInput.Control = LOWORD(wParam) & MK_CONTROL; + dev = getDeviceFromHWnd(hWnd); if (dev) dev->postEventFromUser(event); @@ -242,7 +347,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT if (dev) dev->postEventFromUser(event); - return 0; } case WM_KEYUP: @@ -262,7 +366,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT if (dev) dev->postEventFromUser(event); - return 0; } @@ -283,7 +386,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT // prevent screensaver or monitor powersave mode from starting if ((wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER) + { return 0; + } break; } @@ -328,7 +433,7 @@ CIrrDeviceWin32::CIrrDeviceWin32(video:: // Register Class WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; @@ -356,7 +461,12 @@ CIrrDeviceWin32::CIrrDeviceWin32(video:: DWORD style = WS_POPUP; if (!fullscreen) + { + // Starsonata: Get the whole window (was just a test for now, but will be needed later on) + // style = WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + } AdjustWindowRect(&clientSize, style, FALSE); @@ -527,6 +637,40 @@ void CIrrDeviceWin32::createDriver(video } } +//! MICHA: remove all events pending in the message loop +void CIrrDeviceWin32::clearPendingEvents() +{ + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) + {} + while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) + {} +} + +void CIrrDeviceWin32::minimize() +{ + ShowWindow( HWnd, SW_MINIMIZE ); +} + +void CIrrDeviceWin32::maximize() +{ + ShowWindow( HWnd, SW_MAXIMIZE ); +} + +void CIrrDeviceWin32::restore() +{ + ShowWindow( HWnd, SW_RESTORE ); +} + +bool CIrrDeviceWin32::isMinimized() +{ + return (bool)IsIconic(HWnd); +} + +bool CIrrDeviceWin32::isMaximized() +{ + return (bool)IsZoomed(HWnd); +} //! runs the device. Returns false if device wants to be deleted @@ -543,7 +687,9 @@ bool CIrrDeviceWin32::run() TranslateMessage(&msg); if (ExternalWindow && msg.hwnd == HWnd) + { WndProc(HWnd, msg.message, msg.wParam, msg.lParam); + } else DispatchMessage(&msg); @@ -907,7 +1053,12 @@ void CIrrDeviceWin32::setResizeAble(bool LONG style = WS_POPUP; if (!resize) + { + // Starsonata: Get the whole window (was just a test for now, but will be needed later on) + //style = WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + } else style = WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX; @@ -965,3 +1116,4 @@ IRRLICHT_API IrrlichtDevice* IRRCALLCONV #endif // _IRR_USE_WINDOWS_DEVICE_ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceWin32.h Irrlicht_starsonata/source/Irrlicht/CIrrDeviceWin32.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CIrrDeviceWin32.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CIrrDeviceWin32.h 2008-02-27 00:16:04.000000000 +0100 @@ -65,6 +65,28 @@ namespace irr //! Sets if the window should be resizeable in windowed mode. virtual void setResizeAble(bool resize=false); + // Starsonata, Micha + //! remove all events pending in the message loop + virtual void clearPendingEvents(); + + // starsonata, micha: + //! minimize the application. Only supported on windows so far. + virtual void minimize(); + + //! minimize the application. Only supported on windows so far. + virtual void maximize(); + + //! restore mainwindow to original size. Only supported on windows so far. + virtual void restore(); + + // starsonata, micha: + //! Check if application is minimized. Only supported on windows so far. + virtual bool isMinimized(); + + // starsonata, micha: + //! Check if main window is maximized. Only supported on windows so far. + virtual bool isMaximized(); + //! Implementation of the win32 cursor control class CCursorControl : public gui::ICursorControl { diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CMeshCache.cpp Irrlicht_starsonata/source/Irrlicht/CMeshCache.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CMeshCache.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CMeshCache.cpp 2008-01-18 09:17:16.000000000 +0100 @@ -26,7 +26,6 @@ void CMeshCache::addMesh(const c8* filen MeshEntry e; e.Mesh = mesh; e.Name = filename; - e.Name.make_lower(); Meshes.push_back(e); } @@ -113,7 +112,6 @@ IAnimatedMesh* CMeshCache::getMeshByFile { MeshEntry e; e.Name = filename; - e.Name.make_lower(); s32 id = Meshes.binary_search(e); return (id != -1) ? Meshes[id].Mesh : 0; } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CNullDriver.cpp Irrlicht_starsonata/source/Irrlicht/CNullDriver.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CNullDriver.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CNullDriver.cpp 2008-08-04 00:03:52.000000000 +0200 @@ -602,7 +602,8 @@ void CNullDriver::draw2DImage(video::ITe //! Draws a part of the texture into the rectangle. void CNullDriver::draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect, - video::SColor* colors, bool useAlphaChannelOfTexture) + video::SColor* colors, bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { } @@ -612,7 +613,8 @@ void CNullDriver::draw2DImage(video::ITe void CNullDriver::draw2DImage(video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) + bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CNullDriver.h Irrlicht_starsonata/source/Irrlicht/CNullDriver.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CNullDriver.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CNullDriver.h 2008-08-04 00:03:58.000000000 +0200 @@ -150,12 +150,14 @@ namespace video //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. virtual void draw2DImage(video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect = 0, - SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //! Draws a part of the texture into the rectangle. virtual void draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect = 0, - video::SColor* colors=0, bool useAlphaChannelOfTexture=false); + video::SColor* colors=0, bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //! draw an 2d rectangle virtual void draw2DRectangle(SColor color, const core::rect& pos, const core::rect* clip = 0); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLDriver.cpp Irrlicht_starsonata/source/Irrlicht/COpenGLDriver.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLDriver.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/COpenGLDriver.cpp 2008-08-05 01:50:24.000000000 +0200 @@ -659,7 +659,8 @@ void COpenGLDriver::draw2DImage(video::I const core::position2d& pos, const core::rect& sourceRect, const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) + bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { if (!texture) return; @@ -747,9 +748,13 @@ void COpenGLDriver::draw2DImage(video::I // ok, we've clipped everything. // now draw it. - const core::dimension2d& ss = texture->getOriginalSize(); - core::rect tcoords; + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); + core::rect tcoords; tcoords.UpperLeftCorner.X = (f32)sourcePos.X / (f32)ss.Width; tcoords.UpperLeftCorner.Y = (f32)sourcePos.Y / (f32)ss.Height; tcoords.LowerRightCorner.X = ((f32)sourcePos.X +(f32)sourceSize.Width) / (f32)ss.Width; @@ -765,10 +770,37 @@ void COpenGLDriver::draw2DImage(video::I npos.LowerRightCorner.X = ( poss.LowerRightCorner.X * xFact ) - 1.0f; npos.LowerRightCorner.Y = 1.0f - ( poss.LowerRightCorner.Y * yFact ); - setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); disableTextures(1); if (!setTexture(0, texture)) return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + if ( angleInDegree != 0.f ) + { + f32 cx = (npos.UpperLeftCorner.X + npos.LowerRightCorner.X) / 2; + f32 cy = (npos.UpperLeftCorner.Y + npos.LowerRightCorner.Y) / 2; + + if ( rotationCenter ) + { + cx = npos.UpperLeftCorner.X + ((f32)rotationCenter->X / (f32)(texture->getSize().Width))*npos.getWidth(); + cy = npos.UpperLeftCorner.Y + ((f32)rotationCenter->Y / (f32)(texture->getSize().Height))*npos.getHeight(); + } + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glTranslatef(cx, cy, 0); + + // This is a real bad hack to avoid trouble with the projection matrix. + // I tried to fix it otherwise, but when doing that I break some other part of Irrlicht. + // I suppose it won't be a problem anymore with newer Irrlicht versions and as evil + // as this hack is here - it works. + float hackhackhack=float(renderTargetSize.Width)/float(renderTargetSize.Height); + glScalef(1.0, hackhackhack, 1.0); + + glRotatef(angleInDegree, 0.0, 0.0, 1.0); + glTranslatef(-cx, -cy, 0); + } glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); glBegin(GL_QUADS); @@ -786,6 +818,11 @@ void COpenGLDriver::draw2DImage(video::I glVertex2f(npos.UpperLeftCorner.X, npos.LowerRightCorner.Y); glEnd(); + + if ( angleInDegree != 0.f ) + { + glPopMatrix(); + } } @@ -806,10 +843,10 @@ void COpenGLDriver::draw2DImage(video::I return; const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); disableTextures(1); if (!setTexture(0, texture)) return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); if (clipRect) @@ -822,7 +859,12 @@ void COpenGLDriver::draw2DImage(video::I clipRect->getWidth(),clipRect->getHeight()); } - const core::dimension2d& ss = texture->getOriginalSize(); + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); + core::position2d targetPos(pos); core::position2d sourcePos; core::dimension2d sourceSize; @@ -877,12 +919,18 @@ void COpenGLDriver::draw2DImage(video::I void COpenGLDriver::draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect, - video::SColor* colors, bool useAlphaChannelOfTexture) + video::SColor* colors, bool useAlphaChannelOfTexture + , f32 angleInDegree, const core::position2d * rotationCenter) { if (!texture) return; - const core::dimension2d& ss = texture->getOriginalSize(); + core::dimension2d ss; + if ( texture->hasPaddingForPOT() ) + ss = texture->getSize(); + else + ss = texture->getOriginalSize(); + core::rect tcoords; tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width; tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height; @@ -908,10 +956,9 @@ void COpenGLDriver::draw2DImage(video::I video::SColor* useColor = colors ? colors : temp; - setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, true, useAlphaChannelOfTexture); - disableTextures(1); setTexture(0, texture); + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, true, useAlphaChannelOfTexture); if (clipRect) { @@ -923,6 +970,33 @@ void COpenGLDriver::draw2DImage(video::I clipRect->getWidth(),clipRect->getHeight()); } + if ( angleInDegree != 0.f ) + { + f32 cx = (npos.UpperLeftCorner.X + npos.LowerRightCorner.X) / 2; + f32 cy = (npos.UpperLeftCorner.Y + npos.LowerRightCorner.Y) / 2; + + if ( rotationCenter ) + { + cx = npos.UpperLeftCorner.X + ((f32)rotationCenter->X / (f32)(texture->getSize().Width))*npos.getWidth(); + cy = npos.UpperLeftCorner.Y + ((f32)rotationCenter->Y / (f32)(texture->getSize().Height))*npos.getHeight(); + } + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(cx, cy, 0); + + // This is a real bad hack to avoid trouble with the projection matrix. + // I tried to fix it otherwise, but when doing that I break some other part of Irrlicht. + // I suppose it won't be a problem anymore with newer Irrlicht versions and as evil + // as this hack is here - it works. + float hackhackhack=float(renderTargetSize.Width)/float(renderTargetSize.Height); + glScalef(1.0, hackhackhack, 1.0); + + glRotatef(angleInDegree, 0.0, 0.0, 1.0); + glTranslatef(-cx, -cy, 0); + } + glBegin(GL_QUADS); glColor4ub(useColor[0].getRed(), useColor[0].getGreen(), useColor[0].getBlue(), useColor[0].getAlpha()); @@ -943,6 +1017,12 @@ void COpenGLDriver::draw2DImage(video::I glEnd(); + if ( angleInDegree != 0.f ) + { + glPopMatrix(); + glPopMatrix(); + } + if (clipRect) glDisable(GL_SCISSOR_TEST); } @@ -953,8 +1033,8 @@ void COpenGLDriver::draw2DImage(video::I void COpenGLDriver::draw2DRectangle(SColor color, const core::rect& position, const core::rect* clip) { - setRenderStates2DMode(color.getAlpha() < 255, false, false); disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); core::rect pos = position; @@ -1006,13 +1086,13 @@ void COpenGLDriver::draw2DRectangle(cons npos.LowerRightCorner.X = (f32)(pos.LowerRightCorner.X-xPlus) * xFact; npos.LowerRightCorner.Y = (f32)(yPlus-pos.LowerRightCorner.Y) * yFact; + disableTextures(); + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || colorRightUp.getAlpha() < 255 || colorLeftDown.getAlpha() < 255 || colorRightDown.getAlpha() < 255, false, false); - disableTextures(); - glBegin(GL_QUADS); glColor4ub(colorLeftUp.getRed(), colorLeftUp.getGreen(), colorLeftUp.getBlue(), colorLeftUp.getAlpha()); @@ -1058,9 +1138,10 @@ void COpenGLDriver::draw2DLine(const cor npos_end.X = (f32)(end.X - xPlus) * xFact; npos_end.Y = (f32)(yPlus - end.Y) * yFact; - setRenderStates2DMode(color.getAlpha() < 255, false, false); disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + glBegin(GL_LINES); glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); glVertex2f(npos_start.X, npos_start.Y); @@ -1582,7 +1663,6 @@ void COpenGLDriver::setRenderStates2DMod glDisable(GL_ALPHA_TEST); glCullFace(GL_BACK); - } if (texture) diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLDriver.h Irrlicht_starsonata/source/Irrlicht/COpenGLDriver.h --- irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLDriver.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/COpenGLDriver.h 2008-08-04 00:04:18.000000000 +0200 @@ -122,7 +122,8 @@ namespace video //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. virtual void draw2DImage(video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect = 0, - SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //! draws a set of 2d images, using a color and the alpha /** channel of the texture if desired. The images are drawn @@ -151,7 +152,8 @@ namespace video //! Draws a part of the texture into the rectangle. virtual void draw2DImage(video::ITexture* texture, const core::rect& destRect, const core::rect& sourceRect, const core::rect* clipRect = 0, - video::SColor* colors=0, bool useAlphaChannelOfTexture=false); + video::SColor* colors=0, bool useAlphaChannelOfTexture=false + , f32 angleInDegree=0.f, const core::position2d * rotationCenter=NULL); //! draw an 2d rectangle virtual void draw2DRectangle(SColor color, const core::rect& pos, diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLTexture.cpp Irrlicht_starsonata/source/Irrlicht/COpenGLTexture.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLTexture.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/COpenGLTexture.cpp 2008-05-07 05:05:56.000000000 +0200 @@ -28,6 +28,7 @@ COpenGLTexture::COpenGLTexture(IImage* i : ITexture(name), Driver(driver), Image(0), TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT), PixelType(GL_UNSIGNED_BYTE), HasMipMaps(true), + AutomaticMipmapUpdate(false), HasPaddingForPOT(false), ColorFrameBuffer(0), DepthRenderBuffer(0), StencilRenderBuffer(0), Locks(0) { #ifdef _DEBUG @@ -52,6 +53,7 @@ COpenGLTexture::COpenGLTexture(const cor : ITexture(name), ImageSize(size), Driver(driver), Image(0), TextureName(0), InternalFormat(GL_RGB8), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), HasMipMaps(false), + AutomaticMipmapUpdate(false), HasPaddingForPOT(false), ColorFrameBuffer(0), DepthRenderBuffer(0), StencilRenderBuffer(0), Locks(0) { #ifdef _DEBUG @@ -224,17 +226,27 @@ void COpenGLTexture::getImageData(IImage } core::dimension2d nImageSize; - if (Driver && Driver->queryFeature(EVDF_TEXTURE_NPOT)) - nImageSize=ImageSize; - else + // TEST - disabled to find problems with cards which don't have this feature. + // It's not that useful anyway if it doesn't even work on so many cards. + //if (Driver && Driver->queryFeature(EVDF_TEXTURE_NPOT)) + // nImageSize=ImageSize; + //else { nImageSize.Width = getTextureSizeFromSurfaceSize(ImageSize.Width); nImageSize.Height = getTextureSizeFromSurfaceSize(ImageSize.Height); } + HasPaddingForPOT = false; ECOLOR_FORMAT destFormat = getBestColorFormat(image->getColorFormat()); if (ImageSize==nImageSize) Image = new CImage(destFormat, image); + else if ( Driver->getTextureCreationFlag(ETCF_PAD_NPOT) ) + { + Image = new CImage(destFormat, nImageSize); + // copy data, padding will be left empty + image->copyTo(Image); + HasPaddingForPOT = true; + } else { Image = new CImage(destFormat, nImageSize); diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLTexture.h Irrlicht_starsonata/source/Irrlicht/COpenGLTexture.h --- irrlicht-svn-ss/trunk/source/Irrlicht/COpenGLTexture.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/COpenGLTexture.h 2008-05-07 04:12:54.000000000 +0200 @@ -97,6 +97,10 @@ public: //! Unbind FrameBufferObject (valid only if isFrameBufferObject() returns true). void unbindFrameBufferObject(); + // starsonata, micha + //! returns if the texture was padded to get power of two sizes + virtual bool hasPaddingForPOT() const { return HasPaddingForPOT; } + private: //! get the desired color format based on texture creation flags and the input format. @@ -122,6 +126,7 @@ private: GLenum PixelType; bool HasMipMaps; bool AutomaticMipmapUpdate; + bool HasPaddingForPOT; GLuint ColorFrameBuffer; // for FBO path GLuint DepthRenderBuffer; // for FBO path diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp Irrlicht_starsonata/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp 2008-07-31 00:19:32.000000000 +0200 @@ -0,0 +1,210 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleAnimatedMeshSceneNodeEmitter.h" +#include "IAnimatedMeshSceneNode.h" +#include "IMesh.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleAnimatedMeshSceneNodeEmitter::CParticleAnimatedMeshSceneNodeEmitter( + IAnimatedMeshSceneNode* node, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees ) + : Node(node), TotalVertices(0), MBCount(0), MBNumber(mbNumber), + EveryMeshVertex(everyMeshVertex), UseNormalDirection(useNormalDirection), + NormalDirectionModifier(normalDirectionModifier), Direction(direction), + MinParticlesPerSecond(minParticlesPerSecond), MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + Time(0), Emitted(0), MaxAngleDegrees(maxAngleDegrees) +{ + AnimatedMesh = node->getMesh(); + BaseMesh = AnimatedMesh->getMesh(0); + + TotalVertices = 0; + MBCount = BaseMesh->getMeshBufferCount(); + for( u32 i = 0; i < MBCount; ++i ) + { + VertexPerMeshBufferList.push_back( BaseMesh->getMeshBuffer(i)->getVertexCount() ); + TotalVertices += BaseMesh->getMeshBuffer(i)->getVertexCount(); + } +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleAnimatedMeshSceneNodeEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + f32 perSecond = pps ? (f32)MinParticlesPerSecond + (os::Randomizer::rand() % pps) : MinParticlesPerSecond; + f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond * 2) + amount = MaxParticlesPerSecond * 2; + + // Get Mesh for this frame + IMesh* frameMesh = AnimatedMesh->getMesh( core::floor32(Node->getFrameNr()), + 255, Node->getStartFrame(), Node->getEndFrame() ); + for(u32 i=0; igetMeshBufferCount(); ++j ) + { + for( u32 k=0; kgetMeshBuffer(j)->getVertexCount(); ++k ) + { + switch( frameMesh->getMeshBuffer(j)->getVertexType() ) + { + case video::EVT_STANDARD: + p.pos = ((video::S3DVertex*)frameMesh->getMeshBuffer(j)->getVertices())[k].Pos; + if( UseNormalDirection ) + p.vector = ((video::S3DVertex*)frameMesh->getMeshBuffer(j)->getVertices())[k].Normal / NormalDirectionModifier; + else + p.vector = Direction; + break; + case video::EVT_TANGENTS: + p.pos = ((video::S3DVertexTangents*)frameMesh->getMeshBuffer(j)->getVertices())[k].Pos; + if( UseNormalDirection ) + p.vector = ((video::S3DVertexTangents*)frameMesh->getMeshBuffer(j)->getVertices())[k].Normal / + NormalDirectionModifier; + else + p.vector = Direction; + break; + } + + p.startTime = now; + + if( MaxAngleDegrees ) + { + core::vector3df tgt = p.vector; + tgt.rotateXYBy((os::Randomizer::rand()%(MaxAngleDegrees*2)) - MaxAngleDegrees, core::vector3df()); + tgt.rotateYZBy((os::Randomizer::rand()%(MaxAngleDegrees*2)) - MaxAngleDegrees, core::vector3df()); + tgt.rotateXZBy((os::Randomizer::rand()%(MaxAngleDegrees*2)) - MaxAngleDegrees, core::vector3df()); + p.vector = tgt; + } + + if(MaxLifeTime - MinLifeTime == 0) + p.endTime = now + MinLifeTime; + else + p.endTime = now + MinLifeTime + (os::Randomizer::rand() % (MaxLifeTime - MinLifeTime)); + + p.color = MinStartColor.getInterpolated( + MaxStartColor, (os::Randomizer::rand() % 100) / 100.0f); + + p.startColor = p.color; + p.startVector = p.vector; + + Particles.push_back(p); + } + } + } + else + { + s32 randomMB = 0; + + if( MBNumber < 0 ) + { + randomMB = os::Randomizer::rand() % MBCount; + } + else + { + randomMB = MBNumber; + } + + u32 vertexCount = frameMesh->getMeshBuffer(randomMB)->getVertexCount(); + if ( !vertexCount ) + continue; + u32 vertexNumber = os::Randomizer::rand() % vertexCount; + + switch( frameMesh->getMeshBuffer(randomMB)->getVertexType() ) + { + case video::EVT_STANDARD: + p.pos = ((video::S3DVertex*)frameMesh->getMeshBuffer(randomMB)->getVertices())[vertexNumber].Pos; + if( UseNormalDirection ) + p.vector = ((video::S3DVertex*)frameMesh->getMeshBuffer(randomMB)->getVertices())[vertexNumber].Normal / + NormalDirectionModifier; + else + p.vector = Direction; + break; + case video::EVT_TANGENTS: + p.pos = ((video::S3DVertexTangents*)frameMesh->getMeshBuffer(randomMB)->getVertices())[vertexNumber].Pos; + if( UseNormalDirection ) + p.vector = ((video::S3DVertexTangents*)frameMesh->getMeshBuffer(randomMB)->getVertices())[vertexNumber].Normal / + NormalDirectionModifier; + else + p.vector = Direction; + break; + } + + p.startTime = now; + + if( MaxAngleDegrees ) + { + core::vector3df tgt = Direction; + tgt.rotateXYBy((os::Randomizer::rand()%(MaxAngleDegrees*2)) - MaxAngleDegrees, core::vector3df(0,0,0)); + tgt.rotateYZBy((os::Randomizer::rand()%(MaxAngleDegrees*2)) - MaxAngleDegrees, core::vector3df(0,0,0)); + tgt.rotateXZBy((os::Randomizer::rand()%(MaxAngleDegrees*2)) - MaxAngleDegrees, core::vector3df(0,0,0)); + p.vector = tgt; + } + + if(MaxLifeTime - MinLifeTime == 0) + p.endTime = now + MinLifeTime; + else + p.endTime = now + MinLifeTime + (os::Randomizer::rand() % (MaxLifeTime - MinLifeTime)); + + p.color = MinStartColor.getInterpolated( + MaxStartColor, (os::Randomizer::rand() % 100) / 100.0f); + + p.startColor = p.color; + p.startVector = p.vector; + + Particles.push_back(p); + } + } + + outArray = Particles.pointer(); + + return Particles.size(); + } + + return 0; +} + +//! Set Mesh to emit particles from +void CParticleAnimatedMeshSceneNodeEmitter::setAnimatedMeshSceneNode( IAnimatedMeshSceneNode* node ) +{ + Node = node; + AnimatedMesh = node->getMesh(); + BaseMesh = AnimatedMesh->getMesh(0); + + TotalVertices = 0; + MBCount = BaseMesh->getMeshBufferCount(); + for( u32 i = 0; i < MBCount; ++i ) + { + VertexPerMeshBufferList.push_back( BaseMesh->getMeshBuffer(i)->getVertexCount() ); + TotalVertices += BaseMesh->getMeshBuffer(i)->getVertexCount(); + } +} + +} // end namespace scene +} // end namespace irr + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h Irrlicht_starsonata/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h 2008-06-04 00:40:42.000000000 +0200 @@ -0,0 +1,127 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + +#include "IParticleAnimatedMeshSceneNodeEmitter.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +//! An animated mesh emitter +class CParticleAnimatedMeshSceneNodeEmitter : public IParticleAnimatedMeshSceneNodeEmitter +{ +public: + + //! constructor + CParticleAnimatedMeshSceneNodeEmitter( + IAnimatedMeshSceneNode* node, + bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.0f,-1.0f), + f32 normalDirectionModifier = 100.0f, + s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, + u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0 + ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray); + + //! Set Mesh to emit particles from + virtual void setAnimatedMeshSceneNode( IAnimatedMeshSceneNode* node ); + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection ) { UseNormalDirection = useNormalDirection; } + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) { Direction = newDirection; } + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) { NormalDirectionModifier = normalDirectionModifier; } + + //! Sets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual void setEveryMeshVertex( bool everyMeshVertex ) { EveryMeshVertex = everyMeshVertex; } + + //! Set minimum number of particles the emitter emits per second + virtual void setMinParticlesPerSecond( u32 minPPS ) { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles the emitter emits per second + virtual void setMaxParticlesPerSecond( u32 maxPPS ) { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum starting color for particles + virtual void setMinStartColor( const video::SColor& color ) { MinStartColor = color; } + + //! Set maximum starting color for particles + virtual void setMaxStartColor( const video::SColor& color ) { MaxStartColor = color; } + + //! Get Mesh we're emitting particles from + virtual const IAnimatedMeshSceneNode* getAnimatedMeshSceneNode() const { return Node; } + + //! Get whether to use vertex normal for direciton, or direction specified + virtual bool isUsingNormalDirection() const { return UseNormalDirection; } + + //! Get direction the emitter emits particles + virtual const core::vector3df& getDirection() const { return Direction; } + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const { return NormalDirectionModifier; } + + //! Gets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual bool getEveryMeshVertex() const { return EveryMeshVertex; } + + //! Get the minimum number of particles the emitter emits per second + virtual u32 getMinParticlesPerSecond() const { return MinParticlesPerSecond; } + + //! Get the maximum number of particles the emitter emits per second + virtual u32 getMaxParticlesPerSecond() const { return MaxParticlesPerSecond; } + + //! Get the minimum starting color for particles + virtual const video::SColor& getMinStartColor() const { return MinStartColor; } + + //! Get the maximum starting color for particles + virtual const video::SColor& getMaxStartColor() const { return MaxStartColor; } + +private: + + IAnimatedMeshSceneNode* Node; + IAnimatedMesh* AnimatedMesh; + const IMesh* BaseMesh; + s32 TotalVertices; + u32 MBCount; + s32 MBNumber; + core::array VertexPerMeshBufferList; + + bool EveryMeshVertex; + bool UseNormalDirection; + f32 NormalDirectionModifier; + core::array Particles; + core::vector3df Direction; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + + u32 Time; + u32 Emitted; + s32 MaxAngleDegrees; +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __C_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CParticleAttractionAffector.cpp Irrlicht_starsonata/source/Irrlicht/CParticleAttractionAffector.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CParticleAttractionAffector.cpp 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/source/Irrlicht/CParticleAttractionAffector.cpp 2008-06-04 00:40:34.000000000 +0200 @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleAttractionAffector.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleAttractionAffector::CParticleAttractionAffector( + const core::vector3df& point, f32 speed, bool attract, + bool affectX, bool affectY, bool affectZ ) + : Point(point), Speed(speed), AffectX(affectX), AffectY(affectY), + AffectZ(affectZ), Attract(attract), LastTime(0) +{ +} + + +//! Affects an array of particles. +void CParticleAttractionAffector::affect(u32 now, SParticle* particlearray, u32 count) +{ + if( LastTime == 0 ) + { + LastTime = now; + return; + } + + f32 timeDelta = ( now - LastTime ) / 1000.0f; + LastTime = now; + + if( !Enabled ) + return; + + for(u32 i=0; i everyWhatMillisecond) { Particles.set_used(0); - s32 amount = (s32)((Time / everyWhatMillisecond) + 0.5f); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); Time = 0; SParticle p; const core::vector3df& extent = Box.getExtent(); - if (amount > (s32)MaxParticlesPerSecond*2) + if (amount > MaxParticlesPerSecond*2) amount = MaxParticlesPerSecond * 2; - for (s32 i=0; igetAttributeAsInt("MinParticlesPerSecond"); MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond"); - MinParticlesPerSecond = core::max_(1, MinParticlesPerSecond); - MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1); - MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200); - MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); + MinParticlesPerSecond = core::max_(1u, MinParticlesPerSecond); + MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1u); + MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200u); + MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); MinStartColor = in->getAttributeAsColor("MinStartColor"); MaxStartColor = in->getAttributeAsColor("MaxStartColor"); @@ -147,9 +147,9 @@ s32 CParticleBoxEmitter::deserializeAttr MaxLifeTime = in->getAttributeAsInt("MaxLifeTime"); MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees"); - MinLifeTime = core::max_(0, MinLifeTime); - MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); - MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); + MinLifeTime = core::max_(0u, MinLifeTime); + MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); + MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); return in->findAttribute("MaxAngleDegrees"); } diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CParticleBoxEmitter.h Irrlicht_starsonata/source/Irrlicht/CParticleBoxEmitter.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CParticleBoxEmitter.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CParticleBoxEmitter.h 2008-06-04 00:40:40.000000000 +0200 @@ -1,11 +1,11 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2002-2008 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __C_PARTICLE_BOX_EMITTER_H_INCLUDED__ #define __C_PARTICLE_BOX_EMITTER_H_INCLUDED__ -#include "IParticleEmitter.h" +#include "IParticleBoxEmitter.h" #include "irrArray.h" #include "aabbox3d.h" @@ -15,7 +15,7 @@ namespace scene { //! A default box emitter -class CParticleBoxEmitter : public IParticleEmitter +class CParticleBoxEmitter : public IParticleBoxEmitter { public: @@ -35,23 +35,56 @@ public: //! and returns how much new particles there are. virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray); + //! Set direction the emitter emits particles. + virtual void setDirection( const core::vector3df& newDirection ) { Direction = newDirection; } + + //! Set minimum number of particles emitted per second. + virtual void setMinParticlesPerSecond( u32 minPPS ) { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles emitted per second. + virtual void setMaxParticlesPerSecond( u32 maxPPS ) { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum start color. + virtual void setMinStartColor( const video::SColor& color ) { MinStartColor = color; } + + //! Set maximum start color. + virtual void setMaxStartColor( const video::SColor& color ) { MaxStartColor = color; } + + //! Set box from which the particles are emitted. + virtual void setBox( const core::aabbox3df& box ) { Box = box; } + + //! Gets direction the emitter emits particles. + virtual const core::vector3df& getDirection() const { return Direction; } + + //! Gets minimum number of particles emitted per second. + virtual u32 getMinParticlesPerSecond() const { return MinParticlesPerSecond; } + + //! Gets maximum number of particles emitted per second. + virtual u32 getMaxParticlesPerSecond() const { return MaxParticlesPerSecond; } + + //! Gets minimum start color. + virtual const video::SColor& getMinStartColor() const { return MinStartColor; } + + //! Gets maximum start color. + virtual const video::SColor& getMaxStartColor() const { return MaxStartColor; } + + //! Get box from which the particles are emitted. + virtual const core::aabbox3df& getBox() const { return Box; } + //! Writes attributes of the object. - virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options); + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const; //! Reads attributes of the object. virtual s32 deserializeAttributes(s32 startIndex, io::IAttributes* in, io::SAttributeReadWriteOptions* options); - //! Get emitter type - virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_BOX; } - private: core::array Particles; core::aabbox3df Box; core::vector3df Direction; - s32 MinParticlesPerSecond, MaxParticlesPerSecond; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; video::SColor MinStartColor, MaxStartColor; - s32 MinLifeTime, MaxLifeTime; + u32 MinLifeTime, MaxLifeTime; u32 Time; u32 Emitted; diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CParticleCylinderEmitter.cpp Irrlicht_starsonata/source/Irrlicht/CParticleCylinderEmitter.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CParticleCylinderEmitter.cpp 1970-01-01 01:00:00.000000000 +0100 +++ Irrlicht_starsonata/source/Irrlicht/CParticleCylinderEmitter.cpp 2008-06-04 00:40:36.000000000 +0200 @@ -0,0 +1,108 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleCylinderEmitter.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleCylinderEmitter::CParticleCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees) + : Center(center), Normal(normal), Radius(radius), Length(length), OutlineOnly( outlineOnly ), + Direction(direction), MinParticlesPerSecond(minParticlesPerSecond), + MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), Time(0), Emitted(0), + MaxAngleDegrees(maxAngleDegrees) +{ +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleCylinderEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + f32 perSecond = pps ? (f32)MinParticlesPerSecond + (os::Randomizer::rand() % pps) : MinParticlesPerSecond; + f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond*2) + amount = MaxParticlesPerSecond * 2; + + for(u32 i=0; i Particles; + + core::vector3df Center; + core::vector3df Normal; + f32 Radius; + f32 Length; + bool OutlineOnly; + + core::vector3df Direction; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxSta