diff --git a/source/gui/CButton.cpp b/source/gui/CButton.cpp index b54e891e3a..e5e808aacc 100755 --- a/source/gui/CButton.cpp +++ b/source/gui/CButton.cpp @@ -6,59 +6,61 @@ gee@pyro.nu //#include "stdafx." #include "GUI.h" +#include "CButton.h" // TODO Gee: font.h is temporary. +#include "res/font.h" #include "res/res.h" #include "ogl.h" using namespace std; -// Offsets -DECLARE_SETTINGS_INFO(SButtonSettings) - //------------------------------------------------------------------- // Constructor / Destructor //------------------------------------------------------------------- CButton::CButton() { - // Settings defaults ! -/* m_Settings.m_Disabled = false; - m_Settings.m_Font = "null"; - m_Settings.m_Sprite = "null"; - m_Settings.m_SpriteDisabled = "null"; - m_Settings.m_SpriteOver = "null"; - m_Settings.m_SpritePressed = "null"; - m_Settings.m_TextAlign = EAlign_Center; -// m_Settings.m_TextColor = CColor(); -// m_Settings.m_TextColorDisabled; -// m_Settings.m_TextColorOver; -// m_Settings.m_TextColorPressed; - m_Settings.m_TextValign = EValign_Center; - m_Settings.m_ToolTip = "null"; - m_Settings.m_ToolTipStyle = "null"; -*/ + AddSetting(GUIST_CGUIString, "caption"); + AddSetting(GUIST_CStr, "font"); + AddSetting(GUIST_CStr, "sprite"); + AddSetting(GUIST_CStr, "sprite-over"); + AddSetting(GUIST_CStr, "sprite-pressed"); + AddSetting(GUIST_CStr, "sprite-disabled"); + AddSetting(GUIST_CColor, "textcolor"); + AddSetting(GUIST_CColor, "textcolor-over"); + AddSetting(GUIST_CColor, "textcolor-pressed"); + AddSetting(GUIST_CColor, "textcolor-disabled"); - // Static! Only done once - if (m_SettingsInfo.empty()) - { - // Setup the base ones too - SetupBaseSettingsInfo(m_SettingsInfo); - - GUI_ADD_OFFSET_EXT(SButtonSettings, m_Sprite, "string", "sprite") - GUI_ADD_OFFSET_EXT(SButtonSettings, m_SpriteOver, "string", "sprite-over") - GUI_ADD_OFFSET_EXT(SButtonSettings, m_SpritePressed, "string", "sprite-pressed") - GUI_ADD_OFFSET_EXT(SButtonSettings, m_SpriteDisabled, "string", "sprite-disabled") - } + // Add text + AddText(new SGUIText()); } CButton::~CButton() { } +void CButton::SetupText() +{ + if (!GetGUI()) + return; + + assert(m_GeneratedTexts.size()>=1); + + CStr font; + CGUIString caption; + GUI::GetSetting(this, "caption", caption); + + *m_GeneratedTexts[0] = GetGUI()->GenerateText(caption, CStr("verdana12.fnt"), 0, 0); + + // Set position of text + m_TextPos = m_CachedActualSize.CenterPoint() - m_GeneratedTexts[0]->m_Size/2; +} + void CButton::HandleMessage(const SGUIMessage &Message) { // Important IGUIButtonBehavior::HandleMessage(Message); + IGUITextOwner::HandleMessage(Message); switch (Message.type) { @@ -98,31 +100,24 @@ void CButton::Draw() glDisable(GL_TEXTURE_2D); ////////// - if (GetGUI()) - { - bool useBase = false; + float bz = GetBufferedZ(); - if (!GetBaseSettings().m_Enabled) - { - if (m_Settings.m_SpriteDisabled != CStr("null")) - GetGUI()->DrawSprite(m_Settings.m_SpriteDisabled, GetBufferedZ(), m_CachedActualSize); - else - useBase = true; - } - else - if (m_MouseHovering) - { - if (m_Pressed && m_Settings.m_SpritePressed != CStr("null")) - GetGUI()->DrawSprite(m_Settings.m_SpritePressed, GetBufferedZ(), m_CachedActualSize); - else - if (!m_Pressed && m_Settings.m_SpriteOver != CStr("null")) - GetGUI()->DrawSprite(m_Settings.m_SpriteOver, GetBufferedZ(), m_CachedActualSize); - else - useBase = true; - } - else useBase = true; + CStr sprite, sprite_over, sprite_pressed, sprite_disabled; - if (useBase) - GetGUI()->DrawSprite(m_Settings.m_Sprite, GetBufferedZ(), m_CachedActualSize); - } + GUI::GetSetting(this, "sprite", sprite); + GUI::GetSetting(this, "sprite-over", sprite_over); + GUI::GetSetting(this, "sprite-pressed", sprite_pressed); + GUI::GetSetting(this, "sprite-disabled", sprite_disabled); + + DrawButton(m_CachedActualSize, + bz, + sprite, + sprite_over, + sprite_pressed, + sprite_disabled); + + + CColor color = ChooseColor(); + + IGUITextOwner::Draw(0, color, m_TextPos, bz+0.1f); } diff --git a/source/gui/CButton.h b/source/gui/CButton.h index 01c32db91b..9067dee0c3 100755 --- a/source/gui/CButton.h +++ b/source/gui/CButton.h @@ -33,28 +33,6 @@ gee@pyro.nu // Declarations //-------------------------------------------------------- -/** - * Button Settings - */ -struct SButtonSettings -{ - CStr m_Font; - CStr m_Sprite; - CStr m_SpriteDisabled; - CStr m_SpriteOver; - CStr m_SpritePressed; - EAlign m_TextAlign; - CColor m_TextColor; - CColor m_TextColorDisabled; - CColor m_TextColorOver; - CColor m_TextColorPressed; - EValign m_TextValign; - CStr m_ToolTip; - CStr m_ToolTipStyle; -}; - -/////////////////////////////////////////////////////////////////////////////// - /** * @author Gustav Larsson * @@ -63,9 +41,8 @@ struct SButtonSettings * @see IGUIObject * @see IGUISettingsObject * @see IGUIButtonBehavior - * @see SButtonSettings */ -class CButton : public IGUISettingsObject, public IGUIButtonBehavior +class CButton : public IGUIButtonBehavior, public IGUITextOwner { GUI_OBJECT(CButton) @@ -73,13 +50,6 @@ public: CButton(); virtual ~CButton(); - /** - * Since we're doing multiple inheritance, this is to avoid error message - * - * @return Settings infos - */ - virtual map_Settings GetSettingsInfo() const { return IGUISettingsObject::m_SettingsInfo; } - virtual void ResetStates() { IGUIButtonBehavior::ResetStates(); } /** @@ -93,6 +63,18 @@ public: * Draws the Button */ virtual void Draw(); + +protected: + /** + * Sets up text, should be called every time changes has been + * made that can change the visual. + */ + void SetupText(); + + /** + * Placement of text. + */ + CPos m_TextPos; }; #endif diff --git a/source/gui/CCheckBox.cpp b/source/gui/CCheckBox.cpp new file mode 100755 index 0000000000..51196b49cf --- /dev/null +++ b/source/gui/CCheckBox.cpp @@ -0,0 +1,153 @@ +/* +CCheckBox +by Gustav Larsson +gee@pyro.nu +*/ + +//#include "stdafx." +#include "GUI.h" +#include "CCheckBox.h" + +using namespace std; + +//------------------------------------------------------------------- +// Constructor / Destructor +//------------------------------------------------------------------- +CCheckBox::CCheckBox() +{ +/* bool m_Checked; + CStr m_Font; + CStr m_Sprite; + CStr m_SpriteDisabled; + CStr m_SpriteOver; + CStr m_SpritePressed; + CStr m_Sprite2; + CStr m_Sprite2Disabled; + CStr m_Sprite2Over; + CStr m_Sprite2Pressed; + int m_SquareSide; + EAlign m_TextAlign; + CColor m_TextColor; + CColor m_TextColorDisabled; + CColor m_TextColorOver; + CColor m_TextColorPressed; + EValign m_TextValign; + CStr m_ToolTip; + CStr m_ToolTipStyle; +*/ + AddSetting(GUIST_CGUIString, "caption"); + AddSetting(GUIST_bool, "checked"); + AddSetting(GUIST_CStr, "sprite"); + AddSetting(GUIST_CStr, "sprite-over"); + AddSetting(GUIST_CStr, "sprite-pressed"); + AddSetting(GUIST_CStr, "sprite-disabled"); + AddSetting(GUIST_CStr, "sprite2"); + AddSetting(GUIST_CStr, "sprite2-over"); + AddSetting(GUIST_CStr, "sprite2-pressed"); + AddSetting(GUIST_CStr, "sprite2-disabled"); + AddSetting(GUIST_int, "square-side"); + + // Add text + AddText(new SGUIText()); +} + +CCheckBox::~CCheckBox() +{ +} + +void CCheckBox::SetupText() +{ + if (!GetGUI()) + return; + + assert(m_GeneratedTexts.size()>=1); + + CStr font; + CGUIString caption; + //int square_side; + GUI::GetSetting(this, "caption", caption); + //GUI::GetSetting(this, "square-side", square_side); + + // TODO Gee: Establish buffer zones + *m_GeneratedTexts[0] = GetGUI()->GenerateText(caption, CStr("verdana12.fnt"), m_CachedActualSize.GetWidth()-20, 0); + + // Set position of text + // TODO Gee: Big TODO +// m_TextPos.x = m_CachedActualSize.left + 20; +// m_TextPos.y = m_CachedActualSize.top; +} + +void CCheckBox::HandleMessage(const SGUIMessage &Message) +{ + // Important + IGUIButtonBehavior::HandleMessage(Message); + + switch (Message.type) + { + case GUIM_PRESSED: + { + bool checked; + + GUI::GetSetting(this, "checked", checked); + checked = !checked; + GUI::SetSetting(this, "checked", checked); + + //GetGUI()->TEMPmessage = "Check box " + string((const TCHAR*)m_Name) + " was " + (m_Settings.m_Checked?"checked":"unchecked"); + } break; + + default: + break; + } +} + +void CCheckBox::Draw() +{ + ////////// Gee: janwas, this is just temp to see it + glDisable(GL_TEXTURE_2D); + ////////// + + int square_side; + GUI::GetSetting(this, "square-side", square_side); + + float bz = GetBufferedZ(); + + // Get square + // TODO Gee: edit below when CRect has got "height()" + int middle = (m_CachedActualSize.bottom - m_CachedActualSize.top)/2; + CRect rect; + rect.left = m_CachedActualSize.left + middle - square_side/2; + rect.right = rect.left + square_side; + rect.top = m_CachedActualSize.top + middle - square_side/2; + rect.bottom = rect.top + square_side; + + bool checked; + GUI::GetSetting(this, "checked", checked); + + CStr sprite, sprite_over, sprite_pressed, sprite_disabled; + + if (checked) + { + GUI::GetSetting(this, "sprite2", sprite); + GUI::GetSetting(this, "sprite2-over", sprite_over); + GUI::GetSetting(this, "sprite2-pressed", sprite_pressed); + GUI::GetSetting(this, "sprite2-disabled", sprite_disabled); + } + else + { + GUI::GetSetting(this, "sprite", sprite); + GUI::GetSetting(this, "sprite-over", sprite_over); + GUI::GetSetting(this, "sprite-pressed", sprite_pressed); + GUI::GetSetting(this, "sprite-disabled", sprite_disabled); + } + + DrawButton( rect, + bz, + sprite, + sprite_over, + sprite_pressed, + sprite_disabled); + + CColor color = ChooseColor(); + +// IGUITextOwner::Draw(0, color, m_TextPos, bz+0.1f); +} diff --git a/source/gui/CCheckBox.h b/source/gui/CCheckBox.h new file mode 100755 index 0000000000..1813898e94 --- /dev/null +++ b/source/gui/CCheckBox.h @@ -0,0 +1,75 @@ +/* +GUI Object - Check box +by Gustav Larsson +gee@pyro.nu + +--Overview-- + + GUI Object representing a check box + +--More info-- + + Check GUI.h + +*/ + +#ifndef CCheckBox_H +#define CCheckBox_H + +//-------------------------------------------------------- +// Includes / Compiler directives +//-------------------------------------------------------- +#include "GUI.h" + +//-------------------------------------------------------- +// Macros +//-------------------------------------------------------- + +//-------------------------------------------------------- +// Types +//-------------------------------------------------------- + +//-------------------------------------------------------- +// Declarations +//-------------------------------------------------------- + +/** + * @author Gustav Larsson + * + * CheckBox + * + * @see IGUIObject + * @see IGUISettingsObject + * @see IGUIButtonBehavior + */ +class CCheckBox : public IGUIButtonBehavior, public IGUITextOwner +{ + GUI_OBJECT(CCheckBox) + +public: + CCheckBox(); + virtual ~CCheckBox(); + + virtual void ResetStates() { IGUIButtonBehavior::ResetStates(); } + + /** + * Handle Messages + * + * @param Message GUI Message + */ + virtual void HandleMessage(const SGUIMessage &Message); + + /** + * Draws the control + */ + virtual void Draw(); + +protected: + /** + * Sets up text, should be called every time changes has been + * made that can change the visual. + */ + void SetupText(); +}; + +#endif diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 7c4de48dc2..ddea5c5ecb 100755 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -6,6 +6,13 @@ gee@pyro.nu //#include "stdafx." #include "GUI.h" + +// Types - when including them into the engine. +#include "CButton.h" +#include "CText.h" +#include "CCheckBox.h" +#include "CRadioButton.h" + #include #include #include @@ -15,6 +22,9 @@ gee@pyro.nu #include "XercesErrorHandler.h" #include "Prometheus.h" #include "input.h" +#include "OverlayText.h" +// TODO Gee: Whatever include CRect/CPos/CSize +#include "Overlay.h" #include #include @@ -28,6 +38,12 @@ using namespace std; #pragma comment(lib, "xerces-c_2.lib") #endif +// TODO Gee: how to draw overlays? +void render(COverlayText* overlaytext) +{ + +} + //------------------------------------------------------------------- // called from main loop when (input) events are received. @@ -43,7 +59,7 @@ bool CGUI::HandleEvent(const SDL_Event& ev) { if(ev.type == SDL_MOUSEMOTION) { - m_MouseX = ev.motion.x, m_MouseY = ev.motion.y; + m_MousePos = CPos(ev.motion.x, ev.motion.y); // pNearest will after this point at the hovered object, possibly NULL GUI::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, @@ -51,14 +67,15 @@ bool CGUI::HandleEvent(const SDL_Event& ev) SGUIMessage(GUIM_MOUSE_MOTION)); } - char buf[30]; - sprintf(buf, "type = %d", ev.type); - TEMPmessage = buf; + // TODO Gee: temp-stuff +// char buf[30]; +// sprintf(buf, "type = %d", ev.type); + //TEMPmessage = buf; if (ev.type == SDL_MOUSEBUTTONDOWN) { - sprintf(buf, "button = %d", ev.button.button); - TEMPmessage = buf; + // sprintf(buf, "button = %d", ev.button.button); + //TEMPmessage = buf; } // JW: (pre|post)process omitted; what're they for? why would we need any special button_released handling? @@ -68,6 +85,9 @@ bool CGUI::HandleEvent(const SDL_Event& ev) try { + // TODO Gee: Optimizations needed! + // these two recursive function are quite overhead heavy. + // pNearest will after this point at the hovered object, possibly NULL GUI::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, &IGUIObject::ChooseMouseOverAndClosest, @@ -80,70 +100,79 @@ bool CGUI::HandleEvent(const SDL_Event& ev) &IGUIObject::UpdateMouseOver, pNearest); - //if (ev.type == SDL_MOUSEBUTTONDOWN) + if (ev.type == SDL_MOUSEBUTTONDOWN) { - if (ev.type == SDL_MOUSEBUTTONDOWN) + switch (ev.button.button) { - switch (ev.button.button) - { - case SDL_BUTTON_LEFT: - if (pNearest) - { - pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_PRESS_LEFT)); - - // some temp - CClientArea ca; - bool hidden; - - /*GUI::GetSetting(*this, CStr("backdrop"), CStr("size"), ca); - GUI::GetSetting(*this, CStr("backdrop"), CStr("hidden"), hidden); - - //hidden = !hidden; - ca.pixel.right += 3; - ca.pixel.bottom += 3; - - GUI::SetSetting(*this, CStr("backdrop"), CStr("size"), ca); - GUI::SetSetting(*this, CStr("backdrop"), CStr("hidden"), hidden); - */ } - break; - - case 3: // wheel down - if (pNearest) - { - pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_WHEEL_DOWN)); - } - break; - - case 4: // wheel up - if (pNearest) - { - pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_WHEEL_UP)); - } - break; - - default: - break; - } - - } - else - if (ev.type == SDL_MOUSEBUTTONUP) - { - if (ev.button.button == SDL_BUTTON_LEFT) - { - if (pNearest) - pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_RELEASE_LEFT)); - } - - // Reset all states on all visible objects - GUI<>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, - &IGUIObject::ResetStates); - - // It will have reset the mouse over of the current hovered, so we'll - // have to restore that + case SDL_BUTTON_LEFT: if (pNearest) - pNearest->m_MouseHovering = true; + { + pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_PRESS_LEFT)); + } + + { + // some temp +/* CClientArea ca; + bool hidden; + + GUI::GetSetting(*this, CStr("backdrop43"), CStr("size"), ca); + + //hidden = !hidden; + ca.pixel.right -= 3; + + GUI::SetSetting(*this, CStr("backdrop43"), CStr("size"), ca); +*/ } + break; + + case 3: // wheel down + if (pNearest) + { + pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_WHEEL_DOWN)); + } + break; + + case 4: // wheel up + if (pNearest) + { + pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_WHEEL_UP)); + } + break; + + // TODO Gee: Just temp + case SDL_BUTTON_RIGHT: + { + CClientArea ca; + GUI::GetSetting(*this, CStr("backdrop43"), CStr("size"), ca); + + //hidden = !hidden; + ca.pixel.right -= 3; + + GUI::SetSetting(*this, CStr("backdrop43"), CStr("size"), ca); } + break; + + default: + break; + } + + } + else + if (ev.type == SDL_MOUSEBUTTONUP) + { + if (ev.button.button == SDL_BUTTON_LEFT) + { + if (pNearest) + pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_RELEASE_LEFT)); + } + + // Reset all states on all visible objects + GUI<>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, + &IGUIObject::ResetStates); + + // It will have reset the mouse over of the current hovered, so we'll + // have to restore that + if (pNearest) + pNearest->m_MouseHovering = true; } } catch (PS_RESULT e) @@ -164,7 +193,7 @@ bool CGUI::HandleEvent(const SDL_Event& ev) //------------------------------------------------------------------- // Constructor / Destructor //------------------------------------------------------------------- -CGUI::CGUI() +CGUI::CGUI() : m_InternalNameNumber(0) { m_BaseObject = new CGUIDummyObject; m_BaseObject->SetGUI(this); @@ -198,8 +227,11 @@ void CGUI::Initialize() // Add base types! // You can also add types outside the GUI to extend the flexibility of the GUI. // Prometheus though will have all the object types inserted from here. - AddObjectType("button", &CButton::ConstructObject); - AddObjectType("text", &CText::ConstructObject); + AddObjectType("empty", &CGUIDummyObject::ConstructObject); + AddObjectType("button", &CButton::ConstructObject); + AddObjectType("text", &CText::ConstructObject); + AddObjectType("checkbox", &CCheckBox::ConstructObject); + AddObjectType("radiobutton", &CRadioButton::ConstructObject); } void CGUI::Process() @@ -301,10 +333,12 @@ void CGUI::DrawSprite(const CStr &SpriteName, const CRect &Clipping) { // This is not an error, it's just a choice not to draw any sprite. - if (SpriteName == CStr("null") || SpriteName == CStr()) + if (SpriteName == CStr()) return; - bool DoClipping = (Clipping != CRect(0,0,0,0)); + const char * buf = SpriteName; + + bool DoClipping = (Clipping != CRect()); CGUISprite Sprite; // Fetch real sprite from name @@ -325,6 +359,9 @@ void CGUI::DrawSprite(const CStr &SpriteName, { CRect real = cit->m_Size.GetClientArea(Rect); + glPushMatrix(); + glTranslatef(0.f, 0.f, cit->m_DeltaZ); + glColor3f(cit->m_BackColor.r , cit->m_BackColor.g, cit->m_BackColor.b); //glColor3f((float)real.right/1000.f, 0.5f, 0.5f); @@ -335,6 +372,8 @@ void CGUI::DrawSprite(const CStr &SpriteName, glVertex2i(real.left, real.top); glVertex2i(real.right, real.top); glEnd(); + + glPopMatrix(); } glPopMatrix(); } @@ -356,7 +395,6 @@ void CGUI::Destroy() } delete it->second; - it->second = NULL; } // Clear all @@ -383,6 +421,8 @@ void CGUI::AddObject(IGUIObject* pObject) // Cache tree GUI<>::RecurseObject(0, pObject, &IGUIObject::UpdateCachedSize); + // Loaded + GUI::RecurseObject(0, pObject, &IGUIObject::HandleMessage, SGUIMessage(GUIM_LOAD)); } catch (PS_RESULT e) { @@ -413,10 +453,316 @@ void CGUI::UpdateObjects() bool CGUI::ObjectExists(const CStr &Name) const { - if (m_pAllObjects.count(Name)) - return true; - else - return false; + return m_pAllObjects.count(Name); +} + +// private struct used only in GenerateText(...) +static struct SGenerateTextImage +{ + int m_YFrom, // The images starting location in Y + m_YTo, // The images end location in Y + m_Indentation; // The image width in other words + + // Some help functions + // TODO Gee: CRect => CPoint ? + void SetupSpriteCall(const bool &Left, SGUIText::SSpriteCall &SpriteCall, + const int &width, const int &y, + const CSize &Size, const CStr &TextureName, + const int &BufferZone) + { + // TODO Gee: Temp hardcoded values + SpriteCall.m_Area.top = y+BufferZone; + SpriteCall.m_Area.bottom = y+BufferZone + Size.cy; + + if (Left) + { + SpriteCall.m_Area.left = BufferZone; + SpriteCall.m_Area.right = Size.cx+BufferZone; + } + else + { + SpriteCall.m_Area.left = width-BufferZone - Size.cx; + SpriteCall.m_Area.right = width-BufferZone; + } + + SpriteCall.m_TextureName = TextureName; + + m_YFrom = SpriteCall.m_Area.top-BufferZone; + m_YTo = SpriteCall.m_Area.bottom+BufferZone; + m_Indentation = Size.cx+BufferZone*2; + } +}; + +SGUIText CGUI::GenerateText(const CGUIString &string, /*const CColor &Color, */ + const CStr &Font, const int &Width, const int &BufferZone) +{ + SGUIText Text; // object we're generating + + if (string.m_Words.size() == 0) + return Text; + + int x=BufferZone, y=BufferZone; // drawing pointer + int from=0; + bool done=false; + + // Images on the left or the right side. + vector Images[2]; + int pos_last_img=-1; // Position in the string where last img (either left or right) were encountered. + // in order to avoid duplicate processing. + + // Easier to read. + bool WordWrapping = (Width != 0); + + // Go through string word by word + for (int i=0; i pos_last_img) + { + // Loop left/right + for (int j=0; j<2; ++j) + { + for (vector::const_iterator it = Feedback.m_Images[j].begin(); + it != Feedback.m_Images[j].end(); + ++it) + { + SGUIText::SSpriteCall SpriteCall; + SGenerateTextImage Image; + + // Y is if no other floating images is above, y. Else it is placed + // after the last image, like a stack downwards. + int _y; + if (Images[j].size() > 0) + _y = max(y, Images[j].back().m_YTo); + else + _y = y; + + // TODO Gee: CSize temp + CSize size; size.cx = 100; size.cy = 100; + Image.SetupSpriteCall((j==CGUIString::SFeedback::Left), SpriteCall, Width, _y, size, CStr("white-border"), BufferZone); + + // Check if image is the lowest thing. + Text.m_Size.cy = max(Text.m_Size.cy, Image.m_YTo); + + Images[j].push_back(Image); + Text.m_SpriteCalls.push_back(SpriteCall); + } + } + } + + pos_last_img = max(pos_last_img, i); + + x += Feedback.m_Size.cx; + prelim_line_height = max(prelim_line_height, Feedback.m_Size.cy); + + // If Width is 0, then there's no word-wrapping, disable NewLine. + if ((WordWrapping && (x > Width-BufferZone || Feedback.m_NewLine)) || i == string.m_Words.size()-2) + { + // Change from to i, but first keep a copy of its value. + int temp_from = from; + from = i; + + static const int From=0, To=1; + //int width_from=0, width_to=width; + int width_range[2]; + width_range[From] = BufferZone; + width_range[To] = Width - BufferZone; + + // Floating images are only appicable if word-wrapping is enabled. + if (WordWrapping) + { + // Decide width of the line. We need to iterate our floating images. + // this won't be exact because we're assuming the line_height + // will be as our preliminary calculation said. But that may change, + // although we'd have to add a couple of more loops to try straightening + // this problem out, and it is very unlikely to happen noticably if one + // stuctures his text in a stylistically pure fashion. Even if not, it + // is still quite unlikely it will happen. + // Loop through left and right side, from and to. + for (int j=0; j<2; ++j) + { + for (vector::const_iterator it = Images[j].begin(); + it != Images[j].end(); + ++it) + { + // We're working with two intervals here, the image's and the line height's. + // let's find the union of these two. + int union_from, union_to; + + union_from = max(y, it->m_YFrom); + union_to = min(y+prelim_line_height, it->m_YTo); + + // The union is not ø + if (union_to > union_from) + { + if (j == From) + width_range[From] = max(width_range[From], it->m_Indentation); + else + width_range[To] = min(width_range[To], Width - it->m_Indentation); + } + } + } + } + + // Reset X for the next loop + x = width_range[From]; + + // Now we'll do another loop to figure out the height of + // the line (the height of the largest character). This + // couldn't be determined in the first loop (main loop) + // because it didn't regard images, so we don't know + // if all characters processed, will actually be involved + // in that line. + int line_height=0; + for (int j=temp_from; j<=i; ++j) + { + // We don't want to use Feedback now, so we'll have to use + // another. + CGUIString::SFeedback Feedback2; + + string.GenerateTextCall(Feedback2, Font, /*CColor(),*/ + string.m_Words[j], string.m_Words[j+1]); + + // Append X value. + x += Feedback2.m_Size.cx; + + if (WordWrapping && x > width_range[To] && j!=temp_from && !Feedback2.m_NewLine) + break; + + // Let line_height be the maximum m_Height we encounter. + line_height = max(line_height, Feedback2.m_Size.cy); + + if (WordWrapping && Feedback2.m_NewLine) + break; + } + + // Reset x once more + x = width_range[From]; + + // Do the real processing now + for (int j=temp_from; j<=i; ++j) + { + // We don't want to use Feedback now, so we'll have to use + // another. + CGUIString::SFeedback Feedback2; + + // Defaults + string.GenerateTextCall(Feedback2, Font, /*Color, */ + string.m_Words[j], string.m_Words[j+1]); + + // Iterate all and set X/Y values + // Since X values are not set, we need to make an internal + // iteration with an increment that will append the internal + // x, that is what x_pointer is for. + int x_pointer=0; + + vector::iterator it; + for (it = Feedback2.m_TextCalls.begin(); it != Feedback2.m_TextCalls.end(); ++it) + { + it->m_Pos = CPos(x + x_pointer, y + line_height - it->m_Size.cy); + + x_pointer += it->m_Size.cx; + + if (it->m_pSpriteCall) + { + it->m_pSpriteCall->m_Area = + it->m_pSpriteCall->m_Area + it->m_Pos; + } + } + + // Append X value. + x += Feedback2.m_Size.cx; + + Text.m_Size.cx = max(Text.m_Size.cx, x+BufferZone); + + // The first word overrides the width limit, that we + // do in those cases, are just draw that word even + // though it'll extend the object. + if (WordWrapping) // only if word-wrapping is applicable + { + if (Feedback2.m_NewLine) + { + from = j+1; + break; + } + else + if (x > width_range[To] && j==temp_from) + { + from = j+1; + // do not break, since we want it to be added to m_TextCalls + } + else + if (x > width_range[To]) + { + from = j; + break; + } + } + + // Add the whole Feedback2.m_TextCalls to our m_TextCalls. + Text.m_TextCalls.insert(Text.m_TextCalls.end(), Feedback2.m_TextCalls.begin(), Feedback2.m_TextCalls.end()); + Text.m_SpriteCalls.insert(Text.m_SpriteCalls.end(), Feedback2.m_SpriteCalls.begin(), Feedback2.m_SpriteCalls.end()); + + if (j == string.m_Words.size()-2) + done = true; + } + + // Reset X, and append Y. + x = 0; + y += line_height; + + // Update height of all + Text.m_Size.cy = max(Text.m_Size.cy, y+BufferZone); + + // Now if we entered as from = i, then we want + // i being one minus that, so that it will become + // the same i in the next loop. The difference is that + // we're on a new line now. + i = from-1; + } + } + + return Text; +} + +void CGUI::DrawText(const SGUIText &Text, const CColor &DefaultColor, + const CPos &pos, const float &z) +{ + for (vector::const_iterator it=Text.m_TextCalls.begin(); + it!=Text.m_TextCalls.end(); + ++it) + { + if (it->m_pSpriteCall) + continue; + + COverlayText txt(pos.x+it->m_Pos.x, pos.y+it->m_Pos.y, + z, it->m_Font, it->m_String, + (it->m_UseCustomColor?it->m_Color:DefaultColor)); + render(&txt); + } + + for (vector::const_iterator it=Text.m_SpriteCalls.begin(); + it!=Text.m_SpriteCalls.end(); + ++it) + { + DrawSprite(it->m_TextureName, z, it->m_Area + pos); + } } void CGUI::ReportParseError(const CStr &str, ...) @@ -427,6 +773,8 @@ void CGUI::ReportParseError(const CStr &str, ...) /// g_nemLog("*** GUI Tree Creation Errors"); } + + // Important, set ParseError to true ++m_Errors; /* TODO Gee: (MEGA) @@ -540,7 +888,7 @@ void CGUI::LoadXMLFile(const string &Filename) // XML Reading Xerces Specific Sub-Routines //=================================================================== -void CGUI::Xerces_ReadRootObjects(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadRootObjects(DOMElement *pElement) { // Iterate main children // they should all be elements @@ -558,7 +906,7 @@ void CGUI::Xerces_ReadRootObjects(XERCES_CPP_NAMESPACE::DOMElement *pElement) } } -void CGUI::Xerces_ReadRootSprites(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadRootSprites(DOMElement *pElement) { // Iterate main children // they should all be elements @@ -576,7 +924,7 @@ void CGUI::Xerces_ReadRootSprites(XERCES_CPP_NAMESPACE::DOMElement *pElement) } } -void CGUI::Xerces_ReadRootStyles(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadRootStyles(DOMElement *pElement) { // Iterate main children // they should all be elements @@ -594,7 +942,7 @@ void CGUI::Xerces_ReadRootStyles(XERCES_CPP_NAMESPACE::DOMElement *pElement) } } -void CGUI::Xerces_ReadRootSetup(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadRootSetup(DOMElement *pElement) { // Iterate main children // they should all be , or . @@ -665,7 +1013,6 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent) } else object->LoadStyle(*this, argStyle); } - // @@ -683,6 +1030,10 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent) CStr attr_name = XMLString::transcode( attr->getName() ); CStr attr_value = XMLString::transcode( attr->getValue() ); + // If value is "null", then it is equivalent as never being entered + if (attr_value == CStr("null")) + continue; + // Ignore "type" and "style", we've already checked it if (attr_name == CStr("type") || attr_name == CStr("style") ) continue; @@ -711,10 +1062,11 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent) } } - // Check if name isn't set, report error in that case + // Check if name isn't set, generate an internal name in that case. if (!NameSet) { - // TODO Gee: Generate internal name! + object->SetName(CStr("__internal(") + CStr(m_InternalNameNumber) + CStr(")")); + ++m_InternalNameNumber; } // @@ -759,8 +1111,15 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent) // Thank you CStr =) caption.Trim(PS_TRIM_BOTH); - // Set the setting caption to this - GUI::SetSetting(object, "caption", caption); + try + { + // Set the setting caption to this + object->SetSetting("caption", caption); + } + catch (...) + { + // There is no harm if the object didn't have a "caption" + } } // else // TODO Gee: give warning @@ -779,9 +1138,12 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent) } else { + bool absolute; + GUI::GetSetting(object, "absolute", absolute); + // If the object is absolute, we'll have to get the parent's Z buffered, // and add to that! - if (object->GetBaseSettings().m_Absolute) + if (absolute) { GUI::SetSetting(object, "z", pParent->GetBufferedZ() + 10.f); } @@ -811,7 +1173,7 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent) } } -void CGUI::Xerces_ReadSprite(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadSprite(DOMElement *pElement) { assert(pElement); @@ -862,7 +1224,7 @@ void CGUI::Xerces_ReadSprite(XERCES_CPP_NAMESPACE::DOMElement *pElement) m_Sprites[name] = sprite; } -void CGUI::Xerces_ReadImage(XERCES_CPP_NAMESPACE::DOMElement *pElement, CGUISprite &parent) +void CGUI::Xerces_ReadImage(DOMElement *pElement, CGUISprite &parent) { assert(pElement); @@ -899,6 +1261,16 @@ void CGUI::Xerces_ReadImage(XERCES_CPP_NAMESPACE::DOMElement *pElement, CGUISpri else image.m_Size = ca; } else + if (attr_name == CStr("z-level")) + { + int z_level; + if (!GUI::ParseString(attr_value, z_level)) + { + // TODO Gee: Error + } + else image.m_DeltaZ = (float)z_level/100.f; + } + else if (attr_name == CStr("backcolor")) { CColor color; @@ -923,7 +1295,7 @@ void CGUI::Xerces_ReadImage(XERCES_CPP_NAMESPACE::DOMElement *pElement, CGUISpri parent.AddImage(image); } -void CGUI::Xerces_ReadStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadStyle(DOMElement *pElement) { assert(pElement); @@ -958,7 +1330,7 @@ void CGUI::Xerces_ReadStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement) m_Styles[name] = style; } -void CGUI::Xerces_ReadScrollBarStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement) +void CGUI::Xerces_ReadScrollBarStyle(DOMElement *pElement) { assert(pElement); @@ -978,6 +1350,9 @@ void CGUI::Xerces_ReadScrollBarStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement) CStr attr_name = XMLString::transcode( attr->getName() ); CStr attr_value = XMLString::transcode( attr->getValue() ); + if (attr_value == CStr("null")) + continue; + if (attr_name == CStr("name")) name = attr_value; else @@ -990,6 +1365,79 @@ void CGUI::Xerces_ReadScrollBarStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement) } scrollbar.m_Width = i; } + else + if (attr_name == CStr("minimum-bar-size")) + { + int i; + if (!GUI::ParseString(attr_value, i)) + { + // TODO Gee: Report in log file + } + scrollbar.m_MinimumBarSize = i; + } + else + if (attr_name == CStr("sprite-button-top")) + scrollbar.m_SpriteButtonTop = attr_value; + else + if (attr_name == CStr("sprite-button-top-pressed")) + scrollbar.m_SpriteButtonTopPressed = attr_value; + else + if (attr_name == CStr("sprite-button-top-disabled")) + scrollbar.m_SpriteButtonTopDisabled = attr_value; + else + if (attr_name == CStr("sprite-button-top-over")) + scrollbar.m_SpriteButtonTopOver = attr_value; + else + if (attr_name == CStr("sprite-button-bottom")) + scrollbar.m_SpriteButtonBottom = attr_value; + else + if (attr_name == CStr("sprite-button-bottom-pressed")) + scrollbar.m_SpriteButtonBottomPressed = attr_value; + else + if (attr_name == CStr("sprite-button-bottom-disabled")) + scrollbar.m_SpriteButtonBottomDisabled = attr_value; + else + if (attr_name == CStr("sprite-button-bottom-over")) + scrollbar.m_SpriteButtonBottomOver = attr_value; + else + if (attr_name == CStr("sprite-back-vertical")) + scrollbar.m_SpriteBackVertical = attr_value; + else + if (attr_name == CStr("sprite-bar-vertical")) + scrollbar.m_SpriteBarVertical = attr_value; + else + if (attr_name == CStr("sprite-bar-vertical-over")) + scrollbar.m_SpriteBarVerticalOver = attr_value; + else + if (attr_name == CStr("sprite-bar-vertical-pressed")) + scrollbar.m_SpriteBarVerticalPressed = attr_value; + +/* + CStr m_SpriteButtonTop; + CStr m_SpriteButtonTopPressed; + CStr m_SpriteButtonTopDisabled; + + CStr m_SpriteButtonBottom; + CStr m_SpriteButtonBottomPressed; + CStr m_SpriteButtonBottomDisabled; + + CStr m_SpriteScrollBackHorizontal; + CStr m_SpriteScrollBarHorizontal; + + + CStr m_SpriteButtonLeft; + CStr m_SpriteButtonLeftPressed; + CStr m_SpriteButtonLeftDisabled; + + CStr m_SpriteButtonRight; + CStr m_SpriteButtonRightPressed; + CStr m_SpriteButtonRightDisabled; + + CStr m_SpriteScrollBackVertical; + CStr m_SpriteScrollBarVertical; + +*/ + } // diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index 5b84f7d634..36d05ba19a 100755 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -108,7 +108,18 @@ public: * @param Clipping The sprite shouldn't be drawn outside this rectangle */ void DrawSprite(const CStr &SpriteName, const float &Z, - const CRect &Rect, const CRect &Clipping=CRect(0,0,0,0)); + const CRect &Rect, const CRect &Clipping=CRect()); + + /** + * Draw a SGUIText object + * + * @param Text Text object. + * @param DefaultColor Color used if no tag applied. + * @param pos position + * @param z z value. + */ + void DrawText(const SGUIText &Text, const CColor &DefaultColor, + const CPos &pos, const float &z); /** * Clean up, call this to clean up all memory allocated @@ -169,6 +180,24 @@ public: */ void UpdateResolution(); + /** + * Generate a SGUIText object from the inputted string. + * The function will break down the string and its + * tags to calculate exactly which rendering queries + * will be sent to the Renderer. + * + * Done through the CGUI since it can communicate with + * + * @param Text Text to generate SGUIText object from + * @param Color Default color + * @param Font Default font, notice both Default color and defult font + * can be changed by tags. + * @param Width Width, 0 if no word-wrapping. + * @param BufferZone space between text and edge, and space between text and images. + */ + SGUIText GenerateText(const CGUIString &Text, /*const CColor &Color, */ + const CStr &Font, const int &Width, const int &BufferZone); + private: /** * Updates the object pointers, needs to be called each @@ -385,9 +414,10 @@ private: * ChooseMouseOverAndClosest broadcast - * we'd need to pack this and pNearest in a struct */ - u16 m_MouseX, m_MouseY; + CPos m_MousePos; /// Used when reading in XML files + // TODO Gee: Used? int16 m_Errors; //@} @@ -411,6 +441,14 @@ private: */ map_pObjects m_pAllObjects; + /** + * Number of object that has been given name automatically. + * the name given will be '__internal(#)', the number (#) + * being this variable. When an object's name has been set + * as followed, the value will increment. + */ + int m_InternalNameNumber; + /** * Function pointers to functions that constructs * IGUIObjects by name... For instance m_ObjectTypes["button"] diff --git a/source/gui/CGUIScrollBarVertical.cpp b/source/gui/CGUIScrollBarVertical.cpp index 8764774e56..4b358d073c 100755 --- a/source/gui/CGUIScrollBarVertical.cpp +++ b/source/gui/CGUIScrollBarVertical.cpp @@ -9,81 +9,182 @@ gee@pyro.nu using namespace std; -void CGUIScrollBarVertical::SetPosFromMousePos(int _x, int _y) +CGUIScrollBarVertical::CGUIScrollBarVertical() { - m_Pos = m_PosWhenPressed + ((float)_y-m_BarPressedAtY)/(m_Length-GetStyle().m_Width*2)*2.f; +} + +CGUIScrollBarVertical::~CGUIScrollBarVertical() +{ +} + +void CGUIScrollBarVertical::SetPosFromMousePos(const CPos &mouse) +{ + if (!GetStyle()) + return; + + m_Pos = (m_PosWhenPressed + (float)m_ScrollRange*((float)mouse.y-m_BarPressedAtPos.y)/(m_Length-GetStyle()->m_Width*2)); } void CGUIScrollBarVertical::Draw() { - int StartX = (m_RightAligned)?(m_X-GetStyle().m_Width):(m_X); + if (!GetStyle()) + { + // TODO Gee: Report in error log + return; + } - // Draw background - g_GUI.DrawSprite(GetStyle().m_SpriteScrollBackVertical, m_Z+0.1f, - CRect( StartX, - m_Y+GetStyle().m_Width, - StartX+GetStyle().m_Width, - m_Y+m_Length-GetStyle().m_Width) - ); + if (GetGUI()) + { + CRect outline = GetOuterRect(); - // Draw top button - g_GUI.DrawSprite(GetStyle().m_SpriteButtonTop, m_Z+0.2f, CRect(StartX, m_Y, StartX+GetStyle().m_Width, m_Y+GetStyle().m_Width)); - - // Draw bottom button - g_GUI.DrawSprite(GetStyle().m_SpriteButtonBottom, m_Z+0.2f, CRect(StartX, m_Y+m_Length-GetStyle().m_Width, StartX+GetStyle().m_Width, m_Y+m_Length)); + // Draw background + GetGUI()->DrawSprite(GetStyle()->m_SpriteBackVertical, m_Z+0.1f, + CRect( outline.left, + outline.top+(m_UseEdgeButtons?GetStyle()->m_Width:0), + outline.right, + outline.bottom-(m_UseEdgeButtons?GetStyle()->m_Width:0)) + ); - // Draw bar - if (m_BarPressed) - g_GUI.DrawSprite(GetStyle().m_SpriteScrollBarVertical, m_Z+0.2f, GetBarRect()); - else - g_GUI.DrawSprite(GetStyle().m_SpriteScrollBarVertical, m_Z+0.2f, GetBarRect()); -} + if (m_UseEdgeButtons) + { + // Get Appropriate sprites + CStr button_top, button_bottom; -bool CGUIScrollBarVertical::HandleMessage(const SGUIMessage &Message) + // figure out what sprite to use for top button + if (m_ButtonMinusHovered) + { + if (m_ButtonMinusPressed) + button_top = GUI<>::FallBackSprite(GetStyle()->m_SpriteButtonTopPressed, GetStyle()->m_SpriteButtonTop); + else + button_top = GUI<>::FallBackSprite(GetStyle()->m_SpriteButtonTopOver, GetStyle()->m_SpriteButtonTop); + } + else button_top = GetStyle()->m_SpriteButtonTop; + + // figure out what sprite to use for top button + if (m_ButtonPlusHovered) + { + if (m_ButtonPlusPressed) + button_bottom = GUI<>::FallBackSprite(GetStyle()->m_SpriteButtonBottomPressed, GetStyle()->m_SpriteButtonBottom); + else + button_bottom = GUI<>::FallBackSprite(GetStyle()->m_SpriteButtonBottomOver, GetStyle()->m_SpriteButtonBottom); + } + else button_bottom = GetStyle()->m_SpriteButtonBottom; + + // Draw top button + GetGUI()->DrawSprite(button_top, + m_Z+0.2f, + CRect(outline.left, + outline.top, + outline.right, + outline.top+GetStyle()->m_Width) + ); + + // Draw bottom button + GetGUI()->DrawSprite(button_bottom, + m_Z+0.2f, + CRect(outline.left, + outline.bottom-GetStyle()->m_Width, + outline.right, + outline.bottom) + ); + } + + // Draw bar + if (m_BarPressed) + GetGUI()->DrawSprite(GUI<>::FallBackSprite(GetStyle()->m_SpriteBarVerticalPressed, GetStyle()->m_SpriteBarVertical), + m_Z+0.2f, + GetBarRect()); + else + if (m_BarHovered) + GetGUI()->DrawSprite(GUI<>::FallBackSprite(GetStyle()->m_SpriteBarVerticalOver, GetStyle()->m_SpriteBarVertical), + m_Z+0.2f, + GetBarRect()); + else + GetGUI()->DrawSprite(GetStyle()->m_SpriteBarVertical, + m_Z+0.2f, + GetBarRect()); + } +} + +void CGUIScrollBarVertical::HandleMessage(const SGUIMessage &Message) { IGUIScrollBar::HandleMessage(Message); - -/* switch (Message.type) - { - -*/ return true; } CRect CGUIScrollBarVertical::GetBarRect() const { + CRect ret; + if (!GetStyle()) + return ret; + int size; float from, to; - size = (int)((m_Length-GetStyle().m_Width*2)*m_BarSize); - from = (float)(m_Y+GetStyle().m_Width); - to = (float)(m_Y+m_Length-GetStyle().m_Width-size); + // is edge buttons used? + if (m_UseEdgeButtons) + { + size = (int)((m_Length-GetStyle()->m_Width*2)*m_BarSize); + if (size < GetStyle()->m_MinimumBarSize) + size = GetStyle()->m_MinimumBarSize; + + from = (float)(m_Y+GetStyle()->m_Width); + to = (float)(m_Y+m_Length-GetStyle()->m_Width-size); + } + else + { + size = (int)(m_Length*m_BarSize); + if (size < GetStyle()->m_MinimumBarSize) + size = GetStyle()->m_MinimumBarSize; + + from = (float)(m_Y); + to = (float)(m_Y+m_Length-size); + } // Setup rectangle - CRect ret; - ret.top = (int)(from + (to-from)*m_Pos); + ret.top = (int)(from + (to-from)*((float)m_Pos/(float)(max(1,m_ScrollRange - m_ScrollSpace)))); ret.bottom = ret.top+size; - ret.right = m_X + ((m_RightAligned)?(0):(GetStyle().m_Width)); - ret.left = ret.right - GetStyle().m_Width; + ret.right = m_X + ((m_RightAligned)?(0):(GetStyle()->m_Width)); + ret.left = ret.right - GetStyle()->m_Width; return ret; } -bool CGUIScrollBarVertical::HoveringButtonMinus(int mouse_x, int mouse_y) +CRect CGUIScrollBarVertical::GetOuterRect() const { - int StartX = (m_RightAligned)?(m_X-GetStyle().m_Width):(m_X); + CRect ret; + if (!GetStyle()) + return ret; - return (mouse_x > StartX && - mouse_x < StartX + GetStyle().m_Width && - mouse_y > m_Y && - mouse_y < m_Y + GetStyle().m_Width); + ret.top = m_Y; + ret.bottom = m_Y+m_Length; + ret.right = m_X + ((m_RightAligned)?(0):(GetStyle()->m_Width)); + ret.left = ret.right - GetStyle()->m_Width; + + return ret; } -bool CGUIScrollBarVertical::HoveringButtonPlus(int mouse_x, int mouse_y) +bool CGUIScrollBarVertical::HoveringButtonMinus(const CPos &mouse) { - int StartX = (m_RightAligned)?(m_X-GetStyle().m_Width):(m_X); + if (!GetStyle()) + return false; - return (mouse_x > StartX && - mouse_x < StartX + GetStyle().m_Width && - mouse_y > m_Y + m_Length - GetStyle().m_Width && - mouse_y < m_Y + m_Length); + int StartX = (m_RightAligned)?(m_X-GetStyle()->m_Width):(m_X); + + return (mouse.x >= StartX && + mouse.x <= StartX + GetStyle()->m_Width && + mouse.y >= m_Y && + mouse.y <= m_Y + GetStyle()->m_Width); +} + +bool CGUIScrollBarVertical::HoveringButtonPlus(const CPos &mouse) +{ + if (!GetStyle()) + return false; + + int StartX = (m_RightAligned)?(m_X-GetStyle()->m_Width):(m_X); + + return (mouse.x > StartX && + mouse.x < StartX + GetStyle()->m_Width && + mouse.y > m_Y + m_Length - GetStyle()->m_Width && + mouse.y < m_Y + m_Length); } diff --git a/source/gui/CGUIScrollBarVertical.h b/source/gui/CGUIScrollBarVertical.h index 20da79fd41..573b9b6c19 100755 --- a/source/gui/CGUIScrollBarVertical.h +++ b/source/gui/CGUIScrollBarVertical.h @@ -41,8 +41,8 @@ gee@pyro.nu class CGUIScrollBarVertical : public IGUIScrollBar { public: - CGUIScrollBarVertical() {} - virtual ~CGUIScrollBarVertical() {} + CGUIScrollBarVertical(); + virtual ~CGUIScrollBarVertical(); public: /** @@ -59,22 +59,22 @@ public: * @return true if messages handled the scroll-bar some. False if * the message should be processed by the object. */ - virtual bool HandleMessage(const SGUIMessage &Message); + virtual void HandleMessage(const SGUIMessage &Message); /** * Set m_Pos with mouse_x/y input, i.e. when draggin. */ - virtual void SetPosFromMousePos(int _x, int _y); + virtual void SetPosFromMousePos(const CPos &mouse); /** * @see IGUIScrollBar#HoveringButtonMinus */ - virtual bool HoveringButtonMinus(int m_x, int m_y); + virtual bool HoveringButtonMinus(const CPos &mouse); /** * @see IGUIScrollBar#HoveringButtonPlus */ - virtual bool HoveringButtonPlus(int m_x, int m_y); + virtual bool HoveringButtonPlus(const CPos &mouse); /** * Set Right Aligned @@ -89,6 +89,13 @@ protected: */ virtual CRect GetBarRect() const; + /** + * Get the rectangle of the outline of the scrollbar, every component of the + * scroll-bar should be inside this area. + * @return Rectangle, CRect + */ + virtual CRect GetOuterRect() const; + /** * Should the scroll bar proceed to the left or to the right of the m_X value. * Notice, this has nothing to do with where the owner places it. diff --git a/source/gui/CGUISprite.h b/source/gui/CGUISprite.h index a787e19f7e..c72a52239b 100755 --- a/source/gui/CGUISprite.h +++ b/source/gui/CGUISprite.h @@ -26,6 +26,7 @@ gee@pyro.nu // Includes / Compiler directives //-------------------------------------------------------- #include "GUI.h" +#include "Overlay.h" //-------------------------------------------------------- // Macros @@ -51,6 +52,9 @@ gee@pyro.nu */ struct SGUIImage { + SGUIImage() : m_Border(false), m_DeltaZ(0.f) {} + ~SGUIImage() {} + CStr m_Texture; // Image placement @@ -65,6 +69,13 @@ struct SGUIImage // 0 or 1 pixel border is the only option bool m_Border; + + /** + * Z value modification of the image. + * Inputted in XML as x-level, although it just an easier and safer + * way of declaring delta-z. + */ + float m_DeltaZ; }; /** @@ -87,16 +98,6 @@ public: CGUISprite() {} virtual ~CGUISprite() {} - /** - * Execute a drawing request for this sprite - * - * @param z Draw in what depth. - * @param rect Outer rectangle to draw the collage. - * @param clipping The clipping rectangle, things should only - * be drawn within these perimeters. - */ - //void Draw(const float &z, const CRect &rect, const CRect &clipping); - /** * Adds an image to the sprite collage. * diff --git a/source/gui/CRadioButton.cpp b/source/gui/CRadioButton.cpp new file mode 100755 index 0000000000..e9b6ec8316 --- /dev/null +++ b/source/gui/CRadioButton.cpp @@ -0,0 +1,37 @@ +/* +CCheckBox +by Gustav Larsson +gee@pyro.nu +*/ + +//#include "stdafx." +#include "GUI.h" +#include "CRadioButton.h" + +using namespace std; + +void CRadioButton::HandleMessage(const SGUIMessage &Message) +{ + // Important + IGUIButtonBehavior::HandleMessage(Message); + + switch (Message.type) + { + case GUIM_PRESSED: + for (vector_pObjects::iterator it = GetParent()->ChildrenItBegin(); it != GetParent()->ChildrenItEnd(); ++it) + { + // Notice, if you use other objects within the parent object that has got + // this the "checked", it too will change. Hence NO OTHER OBJECTS THAN + // RADIO BUTTONS SHOULD BE WITHIN IT! + GUI::SetSetting((*it), "checked", false); + } + + GUI::SetSetting(this, "checked", true); + + //GetGUI()->TEMPmessage = "Check box " + string((const TCHAR*)m_Name) + " was " + (m_Settings.m_Checked?"checked":"unchecked"); + break; + + default: + break; + } +} \ No newline at end of file diff --git a/source/gui/CRadioButton.h b/source/gui/CRadioButton.h new file mode 100755 index 0000000000..069436920d --- /dev/null +++ b/source/gui/CRadioButton.h @@ -0,0 +1,49 @@ +/* +GUI Object - Radio Button +by Gustav Larsson +gee@pyro.nu + +--Overview-- + + GUI Object representing a radio button + +--More info-- + + Check GUI.h + +*/ + +#ifndef CRadioButton_H +#define CRadioButton_H + +//-------------------------------------------------------- +// Includes / Compiler directives +//-------------------------------------------------------- +#include "GUI.h" +#include "CCheckBox.h" + +/** + * @author Gustav Larsson + * + * Just like a check box, but it'll nullify its siblings (of the same kind), + * and it won't switch itself. + * + * @see CCheckBox + */ +class CRadioButton : public CCheckBox +{ + GUI_OBJECT(CRadioButton) + + // Let the class freely interact with its siblings + friend class CRadioButton; + +public: + /** + * Handle Messages + * + * @param Message GUI Message + */ + virtual void HandleMessage(const SGUIMessage &Message); +}; + +#endif diff --git a/source/gui/CText.cpp b/source/gui/CText.cpp index e2bdce2fc0..160db555aa 100755 --- a/source/gui/CText.cpp +++ b/source/gui/CText.cpp @@ -6,71 +6,122 @@ gee@pyro.nu //#include "stdafx." #include "GUI.h" +#include "CText.h" // TODO Gee: font.h is temporary. #include "res/font.h" #include "ogl.h" -using namespace std; +// TODO Gee: new +#include "OverlayText.h" -// Offsets -DECLARE_SETTINGS_INFO(STextSettings) +using namespace std; //------------------------------------------------------------------- // Constructor / Destructor //------------------------------------------------------------------- CText::CText() { - // Static! Only done once - if (m_SettingsInfo.empty()) - { - // Setup the base ones too - SetupBaseSettingsInfo(m_SettingsInfo); + AddSetting(GUIST_CGUIString, "caption"); + AddSetting(GUIST_bool, "scrollbar"); + AddSetting(GUIST_CStr, "scrollbar-style"); + AddSetting(GUIST_CStr, "sprite"); + AddSetting(GUIST_CColor, "textcolor"); - GUI_ADD_OFFSET_EXT(STextSettings, m_Sprite, "string", "sprite") - GUI_ADD_OFFSET_EXT(STextSettings, m_ScrollBar, "bool", "scrollbar") - GUI_ADD_OFFSET_EXT(STextSettings, m_ScrollBarStyle, "string", "scrollbar-style") - } + //GUI::SetSetting(this, "ghost", true); + GUI::SetSetting(this, "scrollbar", false); // Add scroll-bar CGUIScrollBarVertical * bar = new CGUIScrollBarVertical(); bar->SetRightAligned(true); + bar->SetUseEdgeButtons(true); AddScrollBar(bar); + + // Add text + AddText(new SGUIText()); } CText::~CText() { } +void CText::SetupText() +{ + if (!GetGUI()) + return; + + assert(m_GeneratedTexts.size()>=1); + + CColor color; + CStr font; + CGUIString caption; + bool scrollbar; + GUI::GetSetting(this, "textcolor", color); + GUI::GetSetting(this, "caption", caption); + GUI::GetSetting(this, "scrollbar", scrollbar); + + int width = m_CachedActualSize.GetWidth(); + // remove scrollbar if applicable + if (scrollbar && GetScrollBar(0).GetStyle()) + width -= GetScrollBar(0).GetStyle()->m_Width; + + *m_GeneratedTexts[0] = GetGUI()->GenerateText(caption, /*color,*/ CStr("verdana12.fnt"), width, 4); + + // Setup scrollbar + if (scrollbar) + { + GetScrollBar(0).SetScrollRange( m_GeneratedTexts[0]->m_Size.cy ); + GetScrollBar(0).SetScrollSpace( m_CachedActualSize.GetHeight() ); + } +} + void CText::HandleMessage(const SGUIMessage &Message) { // TODO Gee: IGUIScrollBarOwner::HandleMessage(Message); + IGUITextOwner::HandleMessage(Message); switch (Message.type) { case GUIM_SETTINGS_UPDATED: - if (Message.value == CStr("size") || Message.value == CStr("z") || - Message.value == CStr("absolute")) + bool scrollbar; + GUI::GetSetting(this, "scrollbar", scrollbar); + + // Update scroll-bar + if (scrollbar && + (Message.value == CStr("size") || Message.value == CStr("z") || + Message.value == CStr("absolute"))) { + GetScrollBar(0).SetX( m_CachedActualSize.right ); GetScrollBar(0).SetY( m_CachedActualSize.top ); GetScrollBar(0).SetZ( GetBufferedZ() ); GetScrollBar(0).SetLength( m_CachedActualSize.bottom - m_CachedActualSize.top ); } - + + // Update scrollbar if (Message.value == CStr("scrollbar-style")) { - GetScrollBar(0).SetScrollBarStyle( GetSettings().m_ScrollBarStyle ); + CStr scrollbar_style; + GUI::GetSetting(this, Message.value, scrollbar_style); + + GetScrollBar(0).SetScrollBarStyle( scrollbar_style ); } + break; case GUIM_MOUSE_WHEEL_DOWN: GetScrollBar(0).ScrollPlus(); + // Since the scroll was changed, let's simulate a mouse movement + // to check if scrollbar now is hovered + HandleMessage(SGUIMessage(GUIM_MOUSE_MOTION)); break; case GUIM_MOUSE_WHEEL_UP: GetScrollBar(0).ScrollMinus(); + // Since the scroll was changed, let's simulate a mouse movement + // to check if scrollbar now is hovered + HandleMessage(SGUIMessage(GUIM_MOUSE_MOTION)); break; default: @@ -84,12 +135,35 @@ void CText::Draw() glDisable(GL_TEXTURE_2D); ////////// + float bz = GetBufferedZ(); + // First call draw on ScrollBarOwner - IGUIScrollBarOwner::Draw(); + bool scrollbar; + GUI::GetSetting(this, "scrollbar", scrollbar); + + if (scrollbar) + { + // Draw scrollbar + IGUIScrollBarOwner::Draw(); + } if (GetGUI()) { - GetGUI()->DrawSprite(m_Settings.m_Sprite, GetBufferedZ(), m_CachedActualSize); - } + CStr sprite; + GUI::GetSetting(this, "sprite", sprite); + GetGUI()->DrawSprite(sprite, bz, m_CachedActualSize); + + int scroll=0; + if (scrollbar) + { + scroll = GetScrollBar(0).GetPos(); + } + + CColor color; + GUI::GetSetting(this, "textcolor", color); + + // Draw text + IGUITextOwner::Draw(0, color, m_CachedActualSize.TopLeft() - CPos(0,scroll), bz+0.1f); + } } diff --git a/source/gui/CText.h b/source/gui/CText.h index fdf3359857..4979a1dcf4 100755 --- a/source/gui/CText.h +++ b/source/gui/CText.h @@ -36,24 +36,6 @@ class IGUIScrollBar; // Declarations //-------------------------------------------------------- -/** - * Text Settings - */ -struct STextSettings -{ - CStr m_Font; - CStr m_Sprite; - EAlign m_TextAlign; - CColor m_TextColor; - EValign m_TextValign; - CStr m_ToolTip; - CStr m_ToolTipStyle; - bool m_ScrollBar; - CStr m_ScrollBarStyle; -}; - -/////////////////////////////////////////////////////////////////////////////// - /** * @author Gustav Larsson * @@ -61,9 +43,8 @@ struct STextSettings * * @see IGUIObject * @see IGUISettingsObject - * @see STextSettings */ -class CText : public IGUISettingsObject, public IGUIScrollBarOwner +class CText : public IGUIScrollBarOwner, public IGUITextOwner { GUI_OBJECT(CText) @@ -71,15 +52,15 @@ public: CText(); virtual ~CText(); - /** - * Since we're doing multiple inheritance, this is to avoid error message - * - * @return Settings infos - */ - virtual map_Settings GetSettingsInfo() const { return IGUISettingsObject::m_SettingsInfo; } - virtual void ResetStates() { IGUIScrollBarOwner::ResetStates(); } +protected: + /** + * Sets up text, should be called every time changes has been + * made that can change the visual. + */ + void SetupText(); + /** * Handle Messages * @@ -91,9 +72,6 @@ public: * Draws the Text */ virtual void Draw(); - - // TODO Gee: Temp! - //CGUIScrollBar m_ScrollBar; }; #endif diff --git a/source/gui/GUI.h b/source/gui/GUI.h index fb5d1fc832..21148284d1 100755 --- a/source/gui/GUI.h +++ b/source/gui/GUI.h @@ -66,16 +66,14 @@ gee@pyro.nu #include "GUIbase.h" #include "GUIutil.h" +#include "GUItext.h" #include "IGUIObject.h" -#include "IGUISettingsObject.h" #include "IGUIButtonBehavior.h" #include "IGUIScrollBarOwner.h" +#include "IGUITextOwner.h" #include "IGUIScrollBar.h" #include "CGUIScrollBarVertical.h" -#include "CButton.h" -#include "CText.h" #include "CGUISprite.h" #include "CGUI.h" - #endif diff --git a/source/gui/GUIbase.h b/source/gui/GUIbase.h index b87cf5be93..cc1535cf91 100755 --- a/source/gui/GUIbase.h +++ b/source/gui/GUIbase.h @@ -36,20 +36,6 @@ class IGUIObject; #define g_GUI CGUI::GetSingleton() // Object settings setups -#define GUI_ADD_OFFSET_GENERIC(si, guiss, _struct, var, type, str) \ - si[CStr(str)].m_Offset = offsetof(_struct, var); \ - si[CStr(str)].m_SettingsStruct = guiss; \ - si[CStr(str)].m_Type = CStr(type); - -#define GUI_ADD_OFFSET_BASE(_struct, var, type, str) \ - GUI_ADD_OFFSET_GENERIC(m_SettingsInfo, GUISS_BASE, _struct, var, type, str) - -#define GUI_ADD_OFFSET_EXT(_struct, var, type, str) \ - GUI_ADD_OFFSET_GENERIC(m_SettingsInfo, GUISS_EXTENDED, _struct, var, type, str) - -// Declares the static variable in IGUISettingsObject<> -#define DECLARE_SETTINGS_INFO(_struct) \ - map_Settings IGUISettingsObject<_struct>::m_SettingsInfo; // Setup an object's ConstructObject function #define GUI_OBJECT(obj) \ @@ -83,10 +69,13 @@ enum EGUIMessageType GUIM_MOUSE_WHEEL_DOWN, GUIM_SETTINGS_UPDATED, // SGUIMessage.m_Value = name of setting GUIM_PRESSED, - GUIM_MOUSE_MOTION + GUIM_MOUSE_MOTION, + GUIM_LOAD // Called when an object is added to the GUI. }; /** + * @author Gustav Larsson + * * Message send to IGUIObject::HandleMessage() in order * to give life to Objects manually with * a derived HandleMessage(). diff --git a/source/gui/GUItext.cpp b/source/gui/GUItext.cpp new file mode 100755 index 0000000000..2a551f77a9 --- /dev/null +++ b/source/gui/GUItext.cpp @@ -0,0 +1,481 @@ +/* +GUI text +by Gustav Larsson +gee@pyro.nu +*/ + +#include "GUI.h" +#include "Parser.h" +#include "OverlayText.h" +#include + +// TODO Gee: Remove, just for temp-output +#include + +static const TCHAR TagStart = '['; +static const TCHAR TagEnd = ']'; + +void CGUIString::SFeedback::Reset() +{ + m_Images[Left].clear(); + m_Images[Right].clear(); + m_TextCalls.clear(); + m_SpriteCalls.clear(); + m_Size = CSize(); + m_NewLine=false; +} + +void CGUIString::GenerateTextCall(SFeedback &Feedback, + const CStr &DefaultFont, /*const CColor &DefaultColor,*/ + const int &from, const int &to) const +{ + // Reset width and height, because they will be determined with incrementation + // or comparisons. + Feedback.Reset(); + + // Check out which text chunk this is within. + //bool match_found = false; + vector::const_iterator itTextChunk; + for (itTextChunk=m_TextChunks.begin(); itTextChunk!=m_TextChunks.end(); ++itTextChunk) + { + // Get the area that is overlapped by both the TextChunk and + // by the from/to inputted. + int _from, _to; + _from = max(from, itTextChunk->m_From); + _to = min(to, itTextChunk->m_To); + + // If from is larger than to, than they are not overlapping + if (_to == _from && itTextChunk->m_From == itTextChunk->m_To && _from > from) + { + // These should never be able to have more than one tag. + assert(itTextChunk->m_Tags.size()==1); + + // Single tags + if (itTextChunk->m_Tags[0].m_TagType == CGUIString::TextChunk::Tag::TAG_IMGLEFT) + { + //if (_from > from) + Feedback.m_Images[SFeedback::Left].push_back(itTextChunk->m_Tags[0].m_TagValue); + } + else + if (itTextChunk->m_Tags[0].m_TagType == CGUIString::TextChunk::Tag::TAG_IMGRIGHT) + { + //if (_from > from) + Feedback.m_Images[SFeedback::Right].push_back(itTextChunk->m_Tags[0].m_TagValue); + } + else + if (itTextChunk->m_Tags[0].m_TagType == CGUIString::TextChunk::Tag::TAG_ICON) + { + //if (_from <= from)continue;; + // We'll need to setup a text-call that will point + // to the icon, this is to be able to iterate + // through the text-calls without having to + // complex the structure ultimately for nothing more. + SGUIText::STextCall TextCall; + + // Also add it to the sprites being rendered. + SGUIText::SSpriteCall SpriteCall; + + CSize size(20,20); + // Query size of icon + // TODO Gee: Temp + + // append width, and make maximum height the height. + Feedback.m_Size.cx += size.cx; + Feedback.m_Size.cy = max(Feedback.m_Size.cy, size.cy); + + // These are also needed later + TextCall.m_Size = size; + SpriteCall.m_Area = size; + + SpriteCall.m_TextureName = CStr("scroll"); + + // Add sprite call + Feedback.m_SpriteCalls.push_back(SpriteCall); + + // Finalize text call + TextCall.m_pSpriteCall = &Feedback.m_SpriteCalls.back(); + + // Add text call + Feedback.m_TextCalls.push_back(TextCall); + } + } + else + if (_to > _from && !Feedback.m_NewLine) + { + SGUIText::STextCall TextCall; + + // Set defaults + TextCall.m_Font = DefaultFont; + TextCall.m_UseCustomColor = false; + + // Extract substring from RawString. + TextCall.m_String = GetRawString().GetSubstring(_from, _to-_from); + + // Go through tags and apply changes. + vector::const_iterator it2; + for (it2 = itTextChunk->m_Tags.begin(); it2 != itTextChunk->m_Tags.end(); ++it2) + { + if (it2->m_TagType == CGUIString::TextChunk::Tag::TAG_COLOR) + { + // Set custom color + TextCall.m_UseCustomColor = true; + GUI::ParseString(it2->m_TagValue, TextCall.m_Color); + } + else + if (it2->m_TagType == CGUIString::TextChunk::Tag::TAG_FONT) + { + TextCall.m_Font = it2->m_TagValue; + } + } + + CSize size; + + COverlayText txt(0, 0, 0, TextCall.m_Font, TextCall.m_String, TextCall.m_Color); + // TODO Gee: Ask Rich to change to (size); + txt.GetOutputStringSize((int&)size.cx, (int&)size.cy); + + // append width, and make maximum height the height. + Feedback.m_Size.cx += size.cx; + Feedback.m_Size.cy = max(Feedback.m_Size.cy, size.cy); + + // These are also needed later + TextCall.m_Size = size; + + if (TextCall.m_String.Length() >= 1) + { + if (TextCall.m_String[0] == '\n') + { + Feedback.m_NewLine = true; + } + } + + // Add text-chunk + Feedback.m_TextCalls.push_back(TextCall); + } + } +} + +bool CGUIString::TextChunk::Tag::SetTagType(const CStr &tagtype) +{ + CStr _tagtype = tagtype.UpperCase(); + + if (_tagtype == CStr("B")) + { + m_TagType = TAG_B; + return true; + } + else + if (_tagtype == CStr("I")) + { + m_TagType = TAG_I; + return true; + } + else + if (_tagtype == CStr("COLOR")) + { + m_TagType = TAG_COLOR; + return true; + } + else + if (_tagtype == CStr("FONT")) + { + m_TagType = TAG_FONT; + return true; + } + else + if (_tagtype == CStr("ICON")) + { + m_TagType = TAG_ICON; + return true; + } + else + if (_tagtype == CStr("IMGLEFT")) + { + m_TagType = TAG_IMGLEFT; + return true; + } + else + if (_tagtype == CStr("IMGRIGHT")) + { + m_TagType = TAG_IMGRIGHT; + return true; + } + + return false; +} + +void CGUIString::SetValue(const CStr &str) +{ + // clear + m_TextChunks.clear(); + m_Words.clear(); + m_RawString = CStr(); + + // Setup parser + CParser Parser; + Parser.InputTaskType("start", "$ident[_=_$value]"); + Parser.InputTaskType("end", "/$ident"); + + _long position = 0; + _long from=0; // the position in the raw string where the last tag ended + _long from_nonraw=0; // like from only in position of the REAL string, with tags. + _long curpos = 0; + + // Current Text Chunk + CGUIString::TextChunk CurrentTextChunk; + + for (;;position = curpos+1) + { + // Find next TagStart character + curpos = str.Find(position, TagStart); + + if (curpos == -1) + { + m_RawString += str.GetSubstring(position, str.Length()-position); + + if (from != m_RawString.Length()) + { + CurrentTextChunk.m_From = from; + CurrentTextChunk.m_To = m_RawString.Length(); + m_TextChunks.push_back(CurrentTextChunk); + } + + break; + } + else + { + // First check if there is another TagStart before a TagEnd, + // in that case it's just a regular TagStart and we can continue. + _long pos_left = str.Find(curpos+1, TagStart); + _long pos_right = str.Find(curpos+1, TagEnd); + + if (pos_right == -1) + { + m_RawString += str.GetSubstring(position, curpos-position+1); + continue; + } + else + if (pos_left != -1 && pos_left < pos_right) + { + m_RawString += str.GetSubstring(position, pos_left-position); + continue; + } + else + { + m_RawString += str.GetSubstring(position, curpos-position); + + // Okay we've found a TagStart and TagEnd, positioned + // at pos and pos_right. Now let's extract the + // interior and try parsing. + CStr tagstr = str.GetSubstring(curpos+1, pos_right-curpos-1); + + CParserLine Line; + Line.ParseString(Parser, (const char*)tagstr); + + // Set to true if the tag is just text. + bool justtext = false; + + if (Line.m_ParseOK) + { + if (Line.m_TaskTypeName == "start") + { + // The tag + TextChunk::Tag tag; + CStr Str_TagType; + + Line.GetArgString(0, (std::string &)Str_TagType); + + if (!tag.SetTagType(Str_TagType)) + { + justtext = true; + } + else + { + // Check for possible value-strings + if (Line.GetArgCount() == 2) + Line.GetArgString(1, (std::string &)tag.m_TagValue); + + // Finalize last + if (curpos != from_nonraw) + { + CurrentTextChunk.m_From = from; + CurrentTextChunk.m_To = from + curpos - from_nonraw; + m_TextChunks.push_back(CurrentTextChunk); + from = CurrentTextChunk.m_To; + } + from_nonraw = pos_right+1; + + // Some tags does not have a closure, and should be + // stored without text. Like a in XML. + if (tag.m_TagType == TextChunk::Tag::TAG_IMGLEFT || + tag.m_TagType == TextChunk::Tag::TAG_IMGRIGHT || + tag.m_TagType == TextChunk::Tag::TAG_ICON) + { + // We need to use a fresh text chunk + // because 'tag' should be the *only* tag. + TextChunk FreshTextChunk; + + // They does not work with the text system. + FreshTextChunk.m_From = from + pos_right+1 - from_nonraw; + FreshTextChunk.m_To = from + pos_right+1 - from_nonraw; + + FreshTextChunk.m_Tags.push_back(tag); + + m_TextChunks.push_back(FreshTextChunk); + } + else + { + // Add that tag, but first, erase previous occurences of the + // same tag. + vector::iterator it; + for (it = CurrentTextChunk.m_Tags.begin(); it != CurrentTextChunk.m_Tags.end(); ++it) + { + if (it->m_TagType == tag.m_TagType) + { + CurrentTextChunk.m_Tags.erase(it); + break; + } + } + + // Add! + CurrentTextChunk.m_Tags.push_back(tag); + } + } + } + else + if (Line.m_TaskTypeName == "end") + { + // The tag + TextChunk::Tag tag; + CStr Str_TagType; + + Line.GetArgString(0, (std::string &)Str_TagType); + + if (!tag.SetTagType(Str_TagType)) + { + justtext = true; + } + else + { + // Finalize the previous chunk + if (curpos != from_nonraw) + { + CurrentTextChunk.m_From = from; + CurrentTextChunk.m_To = from + curpos - from_nonraw; + m_TextChunks.push_back(CurrentTextChunk); + from = CurrentTextChunk.m_To; + } + from_nonraw = pos_right+1; + + // Search for the tag, if it's not added, then + // pass it as plain text. + vector::iterator it; + for (it = CurrentTextChunk.m_Tags.begin(); it != CurrentTextChunk.m_Tags.end(); ++it) + { + if (it->m_TagType == tag.m_TagType) + { + CurrentTextChunk.m_Tags.erase(it); + break; + } + } + } + } + } + else justtext = true; + + if (justtext) + { + // What was within the tags could not be interpreted + // so we'll assume it's just text. + m_RawString += str.GetSubstring(curpos, pos_right-curpos+1); + } + + curpos = pos_right; + + continue; + } + } + } + +#if 1 + + ofstream fout("output1.txt"); + + for (int i=0; i::iterator it; + int last_word = -1; + for (it = m_Words.begin(); it != m_Words.end(); ++it) + { + if (last_word == *it) + m_Words.erase(it); + + last_word = *it; + } +} diff --git a/source/gui/GUItext.h b/source/gui/GUItext.h new file mode 100755 index 0000000000..18a2c3c359 --- /dev/null +++ b/source/gui/GUItext.h @@ -0,0 +1,300 @@ +/* +GUI text, handles text stuff +by Gustav Larsson +gee@pyro.nu + +--Overview-- + + Mainly contains struct SGUIText and friends. + Actual text processing is made in CGUI::GenerateText() + +--More info-- + + Check GUI.h + +*/ + +#ifndef GUItext_H +#define GUItext_H + + +//-------------------------------------------------------- +// Includes / Compiler directives +//-------------------------------------------------------- + +//-------------------------------------------------------- +// Declarations +//-------------------------------------------------------- + +/** + * @author Gustav Larsson + * + * An SGUIText object is a parsed string, divided into + * text-rendering components. Each component, being a + * call to the Renderer. For instance, if you by tags + * change the color, then the GUI will have to make + * individual calls saying it want that color on the + * text. + * + * For instance (this is not the syntax): + * "Hello [b]there[/b] bunny!" + * + * That without word-wrapping would mean 3 components. + * i.e. 3 calls to CRenderer. One drawing "Hello", + * one drawing "there" in bold, and one drawing "bunny!". + */ +struct SGUIText +{ + /** + * @author Gustav Larsson + * + * A sprite call to the CRenderer + */ + struct SSpriteCall + { + /** + * Size and position of sprite + */ + CRect m_Area; + + /** + * Texture name from texture database. + */ + CStr m_TextureName; + }; + + /** + * @author Gustav Larsson + * + * A text call to the CRenderer + */ + struct STextCall + { + STextCall() : + m_Bold(false), m_Italic(false), m_Underlined(false), + m_UseCustomColor(false), m_pSpriteCall(NULL) {} + + /** + * Position + */ + CPos m_Pos; + + /** + * Size + */ + CSize m_Size; + + /** + * The string that is suppose to be rendered. + */ + CStr m_String; + + /** + * Use custom color? If true then m_Color is used, + * else the color inputted will be used. + */ + bool m_UseCustomColor; + + /** + * Color setup + */ + CColor m_Color; + + /** + * Font name + */ + CStr m_Font; + + /** + * Settings + */ + bool m_Bold, m_Italic, m_Underlined; + + /** + * *IF* an icon, than this is not NULL. + */ + SSpriteCall *m_pSpriteCall; + }; + + /** + * List of TextCalls, for instance "Hello", "there!" + */ + std::vector m_TextCalls; + + /** + * List of sprites, or "icons" that should be rendered + * along with the text. + */ + std::vector m_SpriteCalls; + + /** + * Width and height of the whole output, used when setting up + * scrollbars and such. + */ + CSize m_Size; +}; + +/** + * @author Gustav Larsson + * + * String class, substitue for CStr, but that parses + * the tags and builds up a list of all text that will + * be different when outputted. + * + * The difference between CGUIString and SGUIText is that + * CGUIString is a string-class that parses the tags + * when the value is set. The SGUIText is just a container + * which stores the positions and settings of all text-calls + * that will have to be made to the Renderer. + */ +class CGUIString +{ +public: + /** + * @author Gustav Larsson + * + * A chunk of text that represents one call to the renderer. + * In other words, all text in one chunk, will be drawn + * exactly with the same settings. + */ + struct TextChunk + { + /** + * @author Gustav Larsson + * + * A tag looks like this "Hello [B]there[/B] little" + */ + struct Tag + { + /** + * Tag Type + */ + enum TagType + { + TAG_B, + TAG_I, + TAG_FONT, + TAG_SIZE, + TAG_COLOR, + TAG_IMGLEFT, + TAG_IMGRIGHT, + TAG_ICON + }; + + /** + * Set tag from string + * + * @param tagtype TagType by string, like 'IMG' for [IMG] + * @return True if m_TagType was set. + */ + bool SetTagType(const CStr &tagtype); + + /** + * In [B=Hello][/B] + * m_TagType is TAG_B + */ + TagType m_TagType; + + /** + * In [B=Hello][/B] + * m_TagValue is 'Hello' + */ + CStr m_TagValue; + }; + + /** + * m_From and m_To is the range of the string + */ + int m_From, m_To; + + /** + * Tags that are present. [A][B] + */ + std::vector m_Tags; + }; + + /** + * @author Gustav Larsson + * + * All data generated in GenerateTextCall() + */ + struct SFeedback + { + // Constants + const static int Left=0; + const static int Right=1; + + /** + * Reset all member data. + */ + void Reset(); + + /** + * Image stacks, for left and right floating images. + */ + std::vector m_Images[2]; // left and right + + /** + * Text and Sprite Calls. + */ + std::vector m_TextCalls; + std::vector m_SpriteCalls; + + /** + * Width and Height *feedback* + */ + CSize m_Size; + + /** + * If the word inputted was a new line. + */ + bool m_NewLine; + }; + + /** + * Set the value, the string will automatically + * be parsed when set. + */ + void SetValue(const CStr &str); + + /** + * Get String, without tags + */ + CStr GetRawString() const { return m_RawString; } + + /** + * Generate Text Call from specified range. The range + * must span only within ONE TextChunk though. Otherwise + * it can't be fit into a single Text Call + * + * Notice it won't make it complete, you will have to add + * X/Y values and such. + * + * @param Feedback contains all info that is generated. + * @param DefaultFont Default Font + * @param DefaultColor Default Color + * @param from From character n, + * @param to to chacter n. + */ + void GenerateTextCall(SFeedback &Feedback, + const CStr &DefaultFont, /*const CColor &DefaultColor,*/ + const int &from, const int &to) const; + + /** + * Words + */ + std::vector m_Words; + + /** + * TextChunks + */ + std::vector m_TextChunks; + +private: + /** + * The full raw string. Stripped of tags. + */ + CStr m_RawString; +}; + +#endif diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index ac0723c933..695dd699ac 100755 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -10,6 +10,122 @@ gee@pyro.nu using namespace std; +template +bool __ParseString(const CStr &Value, T &tOutput) +{ + // TODO Gee: Unsupported, report error/warning + return false; +} + +template <> +bool __ParseString(const CStr &Value, bool &Output) +{ + if (Value == CStr(_T("true"))) + Output = true; + else + if (Value == CStr(_T("false"))) + Output = false; + else + return false; + + return true; +} + +template <> +bool __ParseString(const CStr &Value, int &Output) +{ + Output = Value.ToInt(); + return true; +} + +template <> +bool __ParseString(const CStr &Value, float &Output) +{ + Output = Value.ToFloat(); + return true; +} + +template <> +bool __ParseString(const CStr &Value, CRect &Output) +{ + // Use the parser to parse the values + CParser parser; + parser.InputTaskType("", "_$value_$value_$value_$value_"); + + string str = (const TCHAR*)Value; + + CParserLine line; + line.ParseString(parser, str); + if (!line.m_ParseOK) + { + // Parsing failed + return false; + } + int values[4]; + for (int i=0; i<4; ++i) + { + if (!line.GetArgInt(i, values[i])) + { + // Parsing failed + return false; + } + } + + // Finally the rectangle values + Output = CRect(values[0], values[1], values[2], values[3]); + return true; +} + +template <> +bool __ParseString(const CStr &Value, CClientArea &Output) +{ + return Output.SetClientArea(Value); +} + +template <> +bool __ParseString(const CStr &Value, CColor &Output) +{ + // Use the parser to parse the values + CParser parser; + parser.InputTaskType("", "_$value_$value_$value_[$value_]"); + + string str = (const TCHAR*)Value; + + CParserLine line; + line.ParseString(parser, str); + if (!line.m_ParseOK) + { + // TODO Gee: Parsing failed + return false; + } + float values[4]; + values[3] = 255.f; // default + for (int i=0; i +bool __ParseString(const CStr &Value, CGUIString &Output) +{ + const char * buf = Value; + + Output.SetValue(Value); + return true; +} + //-------------------------------------------------------- // Help Classes/Structs for the GUI implementation //-------------------------------------------------------- @@ -177,11 +293,6 @@ void CInternalCGUIAccessorBase::QueryResetting(IGUIObject *pObject) GUI<>::RecurseObject(0, pObject, &IGUIObject::ResetStates); } -void * CInternalCGUIAccessorBase::GetStructPointer(IGUIObject *pObject, const EGUISettingsStruct &SettingsStruct) -{ - return pObject->GetStructPointer(SettingsStruct); -} - void CInternalCGUIAccessorBase::HandleMessage(IGUIObject *pObject, const SGUIMessage &message) { pObject->HandleMessage(message); diff --git a/source/gui/GUIutil.h b/source/gui/GUIutil.h index c40c6ccba2..8ea961503c 100755 --- a/source/gui/GUIutil.h +++ b/source/gui/GUIutil.h @@ -23,40 +23,39 @@ gee@pyro.nu //-------------------------------------------------------- #include "GUI.h" #include "Parser.h" +// TODO Gee: New +#include "Overlay.h" //-------------------------------------------------------- // Help Classes/Structs for the GUI //-------------------------------------------------------- -// TEMP -struct CRect -{ - CRect() {} - CRect(int _l, int _t, int _r, int _b) : - left(_l), - top(_t), - right(_r), - bottom(_b) {} - int bottom, top, left, right; - bool operator ==(const CRect &rect) const - { - return (bottom==rect.bottom) && - (top==rect.top) && - (left==rect.left) && - (right==rect.right); - } +class CClientArea; +class CGUIString; - bool operator !=(const CRect &rect) const - { - return !(*this==rect); - } -}; +template +bool __ParseString(const CStr &Value, T &tOutput); -// TEMP -struct CColor -{ - float r, g, b, a; -}; +template <> +bool __ParseString(const CStr &Value, bool &Output); + +template <> +bool __ParseString(const CStr &Value, int &Output); + +template <> +bool __ParseString(const CStr &Value, float &Output); + +template <> +bool __ParseString(const CStr &Value, CRect &Output); + +template <> +bool __ParseString(const CStr &Value, CClientArea &Output); + +template <> +bool __ParseString(const CStr &Value, CColor &Output); + +template <> +bool __ParseString(const CStr &Value, CGUIString &Output); /** * @author Gustav Larsson @@ -66,7 +65,7 @@ struct CColor * You can input the whole value of the Client Area by * string. Like used in the GUI. */ -struct CClientArea +class CClientArea { public: CClientArea(); @@ -128,8 +127,6 @@ protected: /// Wrapper for ResetStates static void QueryResetting(IGUIObject *pObject); - static void * GetStructPointer(IGUIObject *pObject, const EGUISettingsStruct &SettingsStruct); - static void HandleMessage(IGUIObject *pObject, const SGUIMessage &message); }; @@ -167,13 +164,12 @@ public: if (!pObject->SettingExists(Setting)) return PS_SETTING_FAIL; - // Set value - Value = - // *(T*)((size_t)pObject->GetStructPointer(pObject->GetSettingsInfo()[Setting].m_SettingsStruct) + - // pObject->GetSettingsInfo()[Setting].m_Offset); - *(T*)((size_t)GetStructPointer(pObject, pObject->GetSettingsInfo()[Setting].m_SettingsStruct) + - pObject->GetSettingsInfo()[Setting].m_Offset); + if (!pObject->m_Settings.find(Setting)->second.m_pSetting) + return PS_FAIL; + // Set value + Value = *(T*)pObject->m_Settings.find(Setting)->second.m_pSetting; + return PS_OK; } @@ -196,11 +192,7 @@ public: return PS_SETTING_FAIL; // Set value - //*(T*)((size_t)pObject->GetStructPointer(pObject->GetSettingsInfo()[Setting].m_SettingsStruct) + - // pObject->GetSettingsInfo()[Setting].m_Offset) = Value; - *(T*)((size_t)GetStructPointer(pObject, pObject->GetSettingsInfo()[Setting].m_SettingsStruct) + - pObject->GetSettingsInfo()[Setting].m_Offset) = Value; - + *(T*)pObject->m_Settings[Setting].m_pSetting = Value; // // Some settings needs special attention at change @@ -219,12 +211,24 @@ public: //RecurseObject(0, pObject, IGUIObject::ResetStates); } - //pObject->HandleMessage(SGUIMessage(GUIM_SETTINGS_UPDATED, Setting)); HandleMessage(pObject, SGUIMessage(GUIM_SETTINGS_UPDATED, Setting)); return PS_OK; } +#ifdef g_GUI + /** + * Adapter that uses the singleton g_GUI + * Can safely be removed. + */ + static PS_RESULT GetSetting( + const CStr &Object, + const CStr &Setting, T &Value) + { + return GetSetting(g_GUI, Object, Setting, Value); + } +#endif // g_GUI + /** * Retrieves a setting by settings name and object name * @@ -246,6 +250,18 @@ public: return GetSetting(pObject, Setting, Value); } +#ifdef g_GUI + /** + * Adapter that uses the singleton g_GUI + * Can safely be removed. + */ + static PS_RESULT SetSetting( + const CStr &Object, const CStr &Setting, const T &Value) + { + return SetSetting(g_GUI, Object, Setting, Value); + } +#endif // g_GUI + /** * Sets a value by setting and object name using a real * datatype as input @@ -274,8 +290,36 @@ public: return SetSetting(pObject, Setting, Value); } + + /** + * This will return the value of the first sprite if it's not null, + * if it is null, it will return the value of the second sprite, if + * that one is null, then null it is. + * + * @param prim Primary sprite that should be used + * @param sec Secondary sprite if Primary should fail + * @return Resulting string + */ + static CStr FallBackSprite(const CStr &prim, const CStr &sec) + { + // CStr() == empty string, null + return ((prim!=CStr())?(prim):(sec)); + } + + /** + * Same principle as FallBackSprite + * + * @param prim Primary color that should be used + * @param sec Secondary color if Primary should fail + * @return Resulting color + * @see FallBackSprite + */ + static CColor FallBackColor(const CColor &prim, const CColor &sec) + { + // CColor() == null. + return ((prim!=CColor())?(prim):(sec)); + } - /** * Sets a value by setting and object name using a real * datatype as input. @@ -283,7 +327,6 @@ public: * This is just a wrapper for _mem_ParseString() which really * works the magic. * - * @param Type type in string, like "float" or "client area" * @param Value The value in string form, like "0 0 100% 100%" * @param tOutput Parsed value of type T * @return True at success. @@ -292,164 +335,10 @@ public: */ static bool ParseString(const CStr &Value, T &tOutput) { - void *mem = NULL; - - if (!_mem_ParseString(Value, mem)) - return false; - - // Copy from memory - tOutput = *(T*)mem; - - free(mem); - - // TODO Gee: Undefined type - maybe report in log - return true; + return __ParseString(Value, tOutput); } private: - /** - * Input a value in string form, and it will output the result in - * Memory with type T. - * - * @param Type type in string, like "float" or "client area" - * @param Value The value in string form, like "0 0 100% 100%" - * @param Memory Should be NULL, will be constructed within the function. - * @return True at success. - */ - static bool _mem_ParseString(const CStr &Value, void *&Memory) - { -/* if (typeid(T) == typeid(CStr)) - { - tOutput = Value; - return true; - } - else -*/ if (typeid(T) == typeid(bool)) - { - bool _Value; - - if (Value == CStr(_T("true"))) - _Value = true; - else - if (Value == CStr(_T("false"))) - _Value = false; - else - return false; - - Memory = malloc(sizeof(bool)); - memcpy(Memory, (const void*)&_Value, sizeof(bool)); - return true; - } - else - if (typeid(T) == typeid(float)) - { - float _Value = Value.ToFloat(); - // TODO Gee: Okay float value!? - Memory = malloc(sizeof(float)); - memcpy(Memory, (const void*)&_Value, sizeof(float)); - return true; - } - else - if (typeid(T) == typeid(int)) - { - int _Value = Value.ToInt(); - // TODO Gee: Okay float value!? - Memory = malloc(sizeof(int)); - memcpy(Memory, (const void*)&_Value, sizeof(int)); - return true; - } - else - if (typeid(T) == typeid(CRect)) - { - // Use the parser to parse the values - CParser parser; - parser.InputTaskType("", "_$value_$value_$value_$value_"); - - string str = (const TCHAR*)Value; - - CParserLine line; - line.ParseString(parser, str); - if (!line.m_ParseOK) - { - // Parsing failed - return false; - } - int values[4]; - for (int i=0; i<4; ++i) - { - if (!line.GetArgInt(i, values[i])) - { - // Parsing failed - return false; - } - } - - // Finally the rectangle values - CRect _Value(values[0], values[1], values[2], values[3]); - - Memory = malloc(sizeof(CRect)); - memcpy(Memory, (const void*)&_Value, sizeof(CRect)); - return true; - } - else - if (typeid(T) == typeid(CClientArea)) - { - // Get Client Area - CClientArea _Value; - - // Check if valid! - if (!_Value.SetClientArea(Value)) - { - return false; - } - - Memory = malloc(sizeof(CClientArea)); - memcpy(Memory, (const void*)&_Value, sizeof(CClientArea)); - return true; - } - else - if (typeid(T) == typeid(CColor)) - { - // Use the parser to parse the values - CParser parser; - parser.InputTaskType("", "_$value_$value_$value_[$value_]"); - - string str = (const TCHAR*)Value; - - CParserLine line; - line.ParseString(parser, str); - if (!line.m_ParseOK) - { - // TODO Gee: Parsing failed - return false; - } - float values[4]; - values[3] = 255.f; // default - for (int i=0; iGetBaseSettings().m_Hidden) + bool hidden; + GUI::GetSetting(pObject, "hidden", hidden); + + if (hidden) return true; } if (RR & GUIRR_DISABLED) { - if (pObject->GetBaseSettings().m_Enabled) + bool enabled; + GUI::GetSetting(pObject, "enabled", enabled); + + if (!enabled) return true; } if (RR & GUIRR_GHOST) { - if (pObject->GetBaseSettings().m_Ghost) + bool ghost; + GUI::GetSetting(pObject, "ghost", ghost); + + if (ghost) return true; } diff --git a/source/gui/IGUIButtonBehavior.cpp b/source/gui/IGUIButtonBehavior.cpp index f351c55077..60b4d60ace 100755 --- a/source/gui/IGUIButtonBehavior.cpp +++ b/source/gui/IGUIButtonBehavior.cpp @@ -22,38 +22,26 @@ IGUIButtonBehavior::~IGUIButtonBehavior() void IGUIButtonBehavior::HandleMessage(const SGUIMessage &Message) { + // TODO Gee: easier access functions switch (Message.type) { - case GUIM_PREPROCESS: - m_Pressed = false; - break; - -/* case GUIM_POSTPROCESS: - // Check if button has been pressed - if (m_Pressed) - { - // Now check if mouse is released, that means - // it's released outside, since GUIM_MOUSE_RELEASE_LEFT - // would've handled m_Pressed and reset it already - - // Get input structure -/// if (GetGUI()->GetInput()->mRelease(NEMM_BUTTON1)) - { - // Reset - m_Pressed = false; - } - } - break; -*/ case GUIM_MOUSE_PRESS_LEFT: - if (!GetBaseSettings().m_Enabled) + { + bool enabled; + GUI::GetSetting(this, "enabled", enabled); + + if (!enabled) break; m_Pressed = true; - break; + } break; case GUIM_MOUSE_RELEASE_LEFT: - if (!GetBaseSettings().m_Enabled) + { + bool enabled; + GUI::GetSetting(this, "enabled", enabled); + + if (!enabled) break; if (m_Pressed) @@ -62,7 +50,7 @@ void IGUIButtonBehavior::HandleMessage(const SGUIMessage &Message) // BUTTON WAS CLICKED HandleMessage(GUIM_PRESSED); } - break; + } break; case GUIM_SETTINGS_UPDATED: // If it's hidden, then it can't be pressed @@ -74,3 +62,59 @@ void IGUIButtonBehavior::HandleMessage(const SGUIMessage &Message) break; } } + +CColor IGUIButtonBehavior::ChooseColor() +{ + CColor color, color_over, color_pressed, color_disabled; + + // Yes, the object must possess these settings. They are standard + GUI::GetSetting(this, "textcolor", color); + GUI::GetSetting(this, "textcolor-over", color_over); + GUI::GetSetting(this, "textcolor-pressed", color_pressed); + GUI::GetSetting(this, "textcolor-disabled", color_disabled); + + bool enabled; + GUI::GetSetting(this, "enabled", enabled); + + if (!enabled) + { + return GUI<>::FallBackColor(color_disabled, color); + } + else + if (m_MouseHovering) + { + if (m_Pressed) + return GUI<>::FallBackColor(color_pressed, color); + else + return GUI<>::FallBackColor(color_over, color); + } + else return color; +} + +void IGUIButtonBehavior::DrawButton(const CRect &rect, + const float &z, + const CStr &sprite, + const CStr &sprite_over, + const CStr &sprite_pressed, + const CStr &sprite_disabled) +{ + if (GetGUI()) + { + bool enabled; + GUI::GetSetting(this, "enabled", enabled); + + if (!enabled) + { + GetGUI()->DrawSprite(GUI<>::FallBackSprite(sprite_disabled, sprite), z, rect); + } + else + if (m_MouseHovering) + { + if (m_Pressed) + GetGUI()->DrawSprite(GUI<>::FallBackSprite(sprite_pressed, sprite), z, rect); + else + GetGUI()->DrawSprite(GUI<>::FallBackSprite(sprite_over, sprite), z, rect); + } + else GetGUI()->DrawSprite(sprite, z, rect); + } +} \ No newline at end of file diff --git a/source/gui/IGUIButtonBehavior.h b/source/gui/IGUIButtonBehavior.h index 7c119f63c9..140545cc1c 100755 --- a/source/gui/IGUIButtonBehavior.h +++ b/source/gui/IGUIButtonBehavior.h @@ -57,6 +57,34 @@ public: */ virtual void HandleMessage(const SGUIMessage &Message); + /** + * This is a function that lets a button being drawn, + * it regards if it's over, disabled, pressed and such. + * You input sprite names and area and it'll output + * it accordingly. + * + * This class is meant to be used manually in Draw() + * + * @param rect Rectangle in which the sprite should be drawn + * @param z Z-value + * @param sprite Sprite drawn when not pressed, hovered or disabled + * @param sprite_over Sprite drawn when m_MouseHovering is true + * @param sprite_pressed Sprite drawn when m_Pressed is true + * @param sprite_disabled Sprite drawn when "enabled" is false + */ + void DrawButton(const CRect &rect, + const float &z, + const CStr &sprite, + const CStr &sprite_over, + const CStr &sprite_pressed, + const CStr &sprite_disabled); + + /** + * Choosing which color of the following according to + */ + CColor IGUIButtonBehavior::ChooseColor(); + + protected: virtual void ResetStates() { diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index c2c6ab72b3..b02e5153ca 100755 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -14,16 +14,10 @@ gee@pyro.nu using namespace std; -// Offsets -map_Settings IGUIObject::m_SettingsInfo; - //------------------------------------------------------------------- // Implementation Macros //------------------------------------------------------------------- -/*#define _GUI_ADD_OFFSET(type, str, var) \ - SettingsInfo[str].m_Offset = offsetof(IGUIObject, m_BaseSettings) + offsetof(SGUIBaseSettings,var); \ - SettingsInfo[str].m_Type = type; -*/ + //------------------------------------------------------------------- // Constructor / Destructor //------------------------------------------------------------------- @@ -32,21 +26,38 @@ IGUIObject::IGUIObject() : m_pParent(NULL), m_MouseHovering(false) { - // TODO Gee: Remove this when base object is excluded from the recursion routines. - m_BaseSettings.m_Hidden = false; - m_BaseSettings.m_Ghost = false; - m_BaseSettings.m_Enabled = true; - m_BaseSettings.m_Absolute = true; + AddSetting(GUIST_bool, "enabled"); + AddSetting(GUIST_bool, "hidden"); + AddSetting(GUIST_CClientArea, "size"); + AddSetting(GUIST_CStr, "style"); + AddSetting(GUIST_float, "z"); +// AddSetting(GUIST_CGUIString, "caption"); + AddSetting(GUIST_bool, "absolute"); + AddSetting(GUIST_bool, "ghost"); - // Static! Only done once - if (m_SettingsInfo.empty()) - { - SetupBaseSettingsInfo(m_SettingsInfo); - } + // Setup important defaults + GUI::SetSetting(this, "hidden", false); + GUI::SetSetting(this, "ghost", false); + GUI::SetSetting(this, "enabled", true); + GUI::SetSetting(this, "absolute", true); + + + + bool hidden=true; + + GUI::GetSetting(this, "hidden", hidden); + +int hej=23; } IGUIObject::~IGUIObject() { + map::iterator it; + for (it = m_Settings.begin(); it != m_Settings.end(); ++it) + { + if (!it->second.m_pSetting) + delete it->second.m_pSetting; + } } //------------------------------------------------------------------- @@ -116,24 +127,36 @@ void IGUIObject::Destroy() // Is there anything besides the children to destroy? } -void IGUIObject::SetupBaseSettingsInfo(map_Settings &SettingsInfo) +// Notice if using this, the naming convention of GUIST_ should be strict. +#define CASE_TYPE(type) \ + case GUIST_##type: \ + m_Settings[Name].m_pSetting = new type(); \ + break; + +void IGUIObject::AddSetting(const EGUISettingType &Type, const CStr &Name) { -/* _GUI_ADD_OFFSET("bool", "enabled", m_Enabled) - _GUI_ADD_OFFSET("bool", "hidden", m_Hidden) - _GUI_ADD_OFFSET("client area", "size", m_Size) - _GUI_ADD_OFFSET("string", "style", m_Style) - _GUI_ADD_OFFSET("float", "z", m_Z) - _GUI_ADD_OFFSET("string", "caption", m_Caption) - _GUI_ADD_OFFSET("bool", "absolute", m_Absolute) -*/ - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Enabled, "bool", "enabled") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Hidden, "bool", "hidden") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Size, "client area", "size") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Style, "string", "style") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Z, "float", "z") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Caption, "string", "caption") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Absolute, "bool", "absolute") - GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Ghost, "bool", "ghost") + // Is name already taken? + if (m_Settings.count(Name) >= 1) + return; + + // Construct, and set type + m_Settings[Name].m_Type = Type; + + switch (Type) + { + // Construct the setting. + CASE_TYPE(bool) + CASE_TYPE(int) + CASE_TYPE(float) + CASE_TYPE(CClientArea) + CASE_TYPE(CStr) + CASE_TYPE(CColor) + CASE_TYPE(CGUIString) + + default: + // TODO Gee: Report in log, type is not recognized. + break; + } } bool IGUIObject::MouseOver() @@ -141,23 +164,12 @@ bool IGUIObject::MouseOver() if(!GetGUI()) throw PS_NEEDS_PGUI; - u16 mouse_x = GetMouseX(), - mouse_y = GetMouseY(); - - return (mouse_x >= m_CachedActualSize.left && - mouse_x <= m_CachedActualSize.right && - mouse_y >= m_CachedActualSize.top && - mouse_y <= m_CachedActualSize.bottom); + return m_CachedActualSize.PointInside(GetMousePos()); } -u16 IGUIObject::GetMouseX() const +CPos IGUIObject::GetMousePos() const { - return ((GetGUI())?(GetGUI()->m_MouseX):0); -} - -u16 IGUIObject::GetMouseY() const -{ - return ((GetGUI())?(GetGUI()->m_MouseY):0); + return ((GetGUI())?(GetGUI()->m_MousePos):CPos()); } void IGUIObject::UpdateMouseOver(IGUIObject * const &pMouseOver) @@ -190,12 +202,24 @@ void IGUIObject::UpdateMouseOver(IGUIObject * const &pMouseOver) bool IGUIObject::SettingExists(const CStr &Setting) const { // Because GetOffsets will direct dynamically defined - // classes with polymorifsm to respective m_SettingsInfo + // classes with polymorifsm to respective ms_SettingsInfo // we need to make no further updates on this function // in derived classes. - return (GetSettingsInfo().count(Setting) == 1)?true:false; + //return (GetSettingsInfo().count(Setting) >= 1); + return (m_Settings.count(Setting) >= 1); } +#define ADD_TYPE(type) \ + else \ + if (set.m_Type == GUIST_##type) \ + { \ + type _Value; \ + if (!GUI::ParseString(Value, _Value)) \ + throw PS_FAIL; \ + \ + GUI::SetSetting(this, Setting, _Value); \ + } + void IGUIObject::SetSetting(const CStr &Setting, const CStr &Value) { if (!SettingExists(Setting)) @@ -204,48 +228,18 @@ void IGUIObject::SetSetting(const CStr &Setting, const CStr &Value) } // Get setting - SGUISetting set = GetSettingsInfo()[Setting]; + SGUISetting set = m_Settings[Setting]; - if (set.m_Type == CStr(_T("string"))) + if (set.m_Type == GUIST_CStr) { GUI::SetSetting(this, Setting, Value); } - else - if (set.m_Type == CStr(_T("bool"))) - { - bool _Value; - if (!GUI::ParseString(Value, _Value)) - throw PS_FAIL; - - GUI::SetSetting(this, Setting, _Value); - } - else - if (set.m_Type == CStr(_T("float"))) - { - float _Value; - if (!GUI::ParseString(Value, _Value)) - throw PS_FAIL; - - GUI::SetSetting(this, Setting, _Value); - } - else - if (set.m_Type == CStr(_T("rect"))) - { - CRect _Value; - if (!GUI::ParseString(Value, _Value)) - throw PS_FAIL; - - GUI::SetSetting(this, Setting, _Value); - } - else - if (set.m_Type == CStr(_T("client area"))) - { - CClientArea _Value; - if (!GUI::ParseString(Value, _Value)) - throw PS_FAIL; - - GUI::SetSetting(this, Setting, _Value); - } + ADD_TYPE(bool, "bool") + ADD_TYPE(float, "float") + ADD_TYPE(int, "int") + ADD_TYPE(CColor, "color") + ADD_TYPE(CClientArea, "client area") + ADD_TYPE(CGUIString, "text") else { throw PS_FAIL; @@ -285,28 +279,22 @@ IGUIObject *IGUIObject::GetParent() const return m_pParent; } -void * IGUIObject::GetStructPointer(const EGUISettingsStruct &SettingsStruct) const -{ - switch (SettingsStruct) - { - case GUISS_BASE: - return (void*)&m_BaseSettings; - - default: - // TODO Gee: report error - return NULL; - } -} - void IGUIObject::UpdateCachedSize() { + bool absolute; + GUI::GetSetting(this, "absolute", absolute); + + CClientArea ca; + GUI::GetSetting(this, "size", ca); + // If absolute="false" and the object has got a parent, // use its cached size instead of the screen. Notice // it must have just been cached for it to work. - if (m_BaseSettings.m_Absolute == false && m_pParent) - m_CachedActualSize = m_BaseSettings.m_Size.GetClientArea( m_pParent->m_CachedActualSize ); + if (absolute == false && m_pParent) + m_CachedActualSize = ca.GetClientArea(m_pParent->m_CachedActualSize); else - m_CachedActualSize = m_BaseSettings.m_Size.GetClientArea( CRect(0, 0, g_xres, g_yres) ); + m_CachedActualSize = ca.GetClientArea(CRect(0, 0, g_xres, g_yres)); + } void IGUIObject::LoadStyle(CGUI &GUIinstance, const CStr &StyleName) @@ -335,31 +323,39 @@ void IGUIObject::LoadStyle(const SGUIStyle &Style) // since it's generic. catch (PS_RESULT e) { - // was ist das? - e; + // TODO Gee: was ist das? } } } float IGUIObject::GetBufferedZ() const { - if (GetBaseSettings().m_Absolute) - return GetBaseSettings().m_Z; + bool absolute; + GUI::GetSetting(this, "absolute", absolute); + + float Z; + GUI::GetSetting(this, "z", Z); + + if (absolute) + return Z; else { if (GetParent()) - return GetParent()->GetBufferedZ() + GetBaseSettings().m_Z; + return GetParent()->GetBufferedZ() + Z; else - // TODO Gee: Error, no object should be relative with a parent! - return GetBaseSettings().m_Z; + // TODO Gee: Error, no object should be relative without a parent! + return Z; } } // TODO Gee: keep this function and all??? void IGUIObject::CheckSettingsValidity() { + bool hidden; + GUI::GetSetting(this, "hidden", hidden); + // If we hide an object, reset many of its parts - if (GetBaseSettings().m_Hidden) + if (hidden) { // Simulate that no object is hovered for this object and all its children // why? because it's diff --git a/source/gui/IGUIObject.h b/source/gui/IGUIObject.h index 7030f9c46c..a4beb67df7 100755 --- a/source/gui/IGUIObject.h +++ b/source/gui/IGUIObject.h @@ -63,17 +63,39 @@ typedef std::map map_Settings; enum EAlign { EAlign_Left, EAlign_Right, EAlign_Center }; enum EValign { EValign_Top, EValign_Bottom, EValign_Center }; +/** + * Setting Type + * @see SGUISetting + * + * For use of later macros, all names should be GUIST_ followed + * by the code name (case sensitive!). + */ +enum EGUISettingType +{ + GUIST_bool, + GUIST_int, + GUIST_float, + GUIST_CColor, + GUIST_CClientArea, + GUIST_CGUIString, + GUIST_CStr +}; + /** * @author Gustav Larsson * - * Stores the information where to find a variable - * in a GUI-Object object, also what type it is. + * A GUI Setting is anything that can be inputted from XML as + * -attributes (with exceptions). For instance: + * + * + * "style" will be a SGUISetting. */ struct SGUISetting { - size_t m_Offset; // The offset from IGUIObject to the variable (not from SGUIBaseSettings or similar) - EGUISettingsStruct m_SettingsStruct; - CStr m_Type; // "string" or maybe "int" + SGUISetting() : m_pSetting(NULL) {} + + void *m_pSetting; + EGUISettingType m_Type; }; /** @@ -83,8 +105,9 @@ struct SGUISetting * in their m_BaseSettings * Instructions can be found in the documentations. */ -struct SGUIBaseSettings +/*struct SGUIBaseSettings { + //int banan; bool m_Absolute; CStr m_Caption; // Is usually set within an XML element and not in the attributes bool m_Enabled; @@ -93,7 +116,7 @@ struct SGUIBaseSettings CClientArea m_Size; CStr m_Style; float m_Z; -}; +};*/ ////////////////////////////////////////////////////////// @@ -108,22 +131,11 @@ class IGUIObject friend class CGUI; friend class CInternalCGUIAccessorBase; friend class IGUIScrollBar; -#ifndef _MSC_VER - template -#endif - friend class GUI; public: IGUIObject(); virtual ~IGUIObject(); - /** - * Get offsets - * - * @return Retrieves settings info - */ - virtual map_Settings GetSettingsInfo() const { return m_SettingsInfo; } - /** * Checks if mouse is hovering this object. * The mouse position is cached in CGUI. @@ -193,8 +205,6 @@ public: //-------------------------------------------------------- //@{ - SGUIBaseSettings GetBaseSettings() const { return m_BaseSettings; } - /** * Checks if settings exists, only available for derived * classes that has this set up, that's why the base @@ -231,7 +241,7 @@ public: * * @param SettingsInfo Pointers that should be filled with base variables */ - void SetupBaseSettingsInfo(map_Settings &SettingsInfo); + //void SetupBaseSettingsInfo(map_Settings &SettingsInfo); /** * Set a setting by string, regardless of what type it is. @@ -259,6 +269,14 @@ protected: //-------------------------------------------------------- //@{ + /** + * Add a setting to m_Settings + * + * @param Type Setting type + * @param Name Setting reference name + */ + void AddSetting(const EGUISettingType &Type, const CStr &Name); + /** * Calls Destroy on all children, and deallocates all memory. * MEGA TODO Should it destroy it's children? @@ -271,7 +289,7 @@ protected: * * @param Message GUI Message */ - virtual void HandleMessage(const SGUIMessage &Message)=0; + virtual void HandleMessage(const SGUIMessage &Message) {}; /** * Draws the object. @@ -305,7 +323,7 @@ protected: * * @return Actual Z value on the screen. */ - float GetBufferedZ() const; + virtual float GetBufferedZ() const; // This is done internally CGUI *GetGUI() { return m_pGUI; } @@ -342,11 +360,12 @@ protected: * * @param SettingsStruct tells us which pointer ot return */ - virtual void *GetStructPointer(const EGUISettingsStruct &SettingsStruct) const; + //virtual void *GetStructPointer(const EGUISettingsStruct &SettingsStruct) const; - // Get cached mouse x/y from CGUI - u16 GetMouseX() const; - u16 GetMouseY() const; + /** + * Get Mouse from CGUI. + */ + CPos GetMousePos() const; /** * Cached size, real size m_Size is actually dependent on resolution @@ -402,7 +421,7 @@ protected: IGUIObject *m_pParent; /// Base settings - SGUIBaseSettings m_BaseSettings; + //SGUIBaseSettings m_BaseSettings; /** * This is an array of true or false, each element is associated with @@ -429,7 +448,18 @@ protected: * note! @uNOT from SGUIBaseSettings to * m_Frozen! */ - static map_Settings m_SettingsInfo; + //static map_Settings ms_SettingsInfo; + + /** + * Settings pool, all an object's settings are located here + * If a derived object has got more settings that the base + * settings, it's becasue they have a new version of the + * function SetupSettings(). + * + * @see SetupSettings() + */ + public: + std::map m_Settings; private: /// An object can't function stand alone @@ -441,10 +471,13 @@ private: * @author Gustav Larsson * * Dummy object used primarily for the root object - * which isn't a *real* object in the GUI. + * or objects of type 'empty' */ class CGUIDummyObject : public IGUIObject { + GUI_OBJECT(CGUIDummyObject) + +public: virtual void HandleMessage(const SGUIMessage &Message) {} virtual void Draw() {} }; diff --git a/source/gui/IGUIScrollBar.cpp b/source/gui/IGUIScrollBar.cpp index 24ddd95cae..455f12b7b5 100755 --- a/source/gui/IGUIScrollBar.cpp +++ b/source/gui/IGUIScrollBar.cpp @@ -12,7 +12,18 @@ using namespace std; //------------------------------------------------------------------- // IGUIScrollBar //------------------------------------------------------------------- -IGUIScrollBar::IGUIScrollBar() : m_pStyle(NULL), m_X(300), m_Y(300), m_Length(200), m_Width(20), m_BarSize(0.5), m_Pos(0.5) +IGUIScrollBar::IGUIScrollBar() : m_pStyle(NULL), m_pGUI(NULL), + m_X(300), m_Y(300), + m_ScrollRange(1), m_ScrollSpace(0), // MaxPos: not 0, due to division. + m_Length(200), m_Width(20), + m_BarSize(0.5), m_Pos(0), + m_UseEdgeButtons(true), + m_ButtonPlusPressed(false), + m_ButtonMinusPressed(false), + m_ButtonPlusHovered(false), + m_ButtonMinusHovered(false), + m_BarHovered(false), + m_BarPressed(false) { } @@ -20,72 +31,122 @@ IGUIScrollBar::~IGUIScrollBar() { } -const SGUIScrollBarStyle & IGUIScrollBar::GetStyle() const +void IGUIScrollBar::SetupBarSize() +{ + m_BarSize = min((float)m_ScrollSpace/(float)m_ScrollRange, 1.f); +} + +const SGUIScrollBarStyle *IGUIScrollBar::GetStyle() const { if (!m_pHostObject) - return SGUIScrollBarStyle(); + return NULL; return m_pHostObject->GetScrollBarStyle(m_ScrollBarStyle); } -void IGUIScrollBar::UpdatePosBoundaries() -{ - if (m_Pos > 1.f) - m_Pos = 1.f; - else - if (m_Pos < 0.f) - m_Pos = 0.f; +CGUI *IGUIScrollBar::GetGUI() const +{ + if (!m_pHostObject) + return NULL; + + return m_pHostObject->GetGUI(); } -bool IGUIScrollBar::HandleMessage(const SGUIMessage &Message) +void IGUIScrollBar::UpdatePosBoundaries() +{ + if (m_Pos < 0 || + m_ScrollRange < m_ScrollSpace) // <= scrolling not applicable + m_Pos = 0; + else + if (m_Pos > m_ScrollRange - m_ScrollSpace) + m_Pos = m_ScrollRange - m_ScrollSpace; +} + +void IGUIScrollBar::HandleMessage(const SGUIMessage &Message) { switch (Message.type) { case GUIM_MOUSE_MOTION: - if (m_BarPressed) { - SetPosFromMousePos(m_pHostObject->GetMouseX(), m_pHostObject->GetMouseY()); - UpdatePosBoundaries(); - } - break; + // TODO Gee: Optimizations needed! + + CPos mouse = m_pHostObject->GetMousePos(); + + // If bar is being dragged + if (m_BarPressed) + { + SetPosFromMousePos(mouse); + UpdatePosBoundaries(); + } + + CRect bar_rect = GetBarRect(); + // check if components are being hovered + m_BarHovered = bar_rect.PointInside(mouse); + + m_ButtonMinusHovered = HoveringButtonMinus(m_pHostObject->GetMousePos()); + m_ButtonPlusHovered = HoveringButtonPlus(m_pHostObject->GetMousePos()); + + if (!m_ButtonMinusHovered) + m_ButtonMinusPressed = false; + + if (!m_ButtonPlusHovered) + m_ButtonPlusPressed = false; + } break; case GUIM_MOUSE_PRESS_LEFT: { if (!m_pHostObject) break; - int mouse_x = m_pHostObject->GetMouseX(), - mouse_y = m_pHostObject->GetMouseY(); + CPos mouse = m_pHostObject->GetMousePos(); // if bar is pressed - if (mouse_x >= GetBarRect().left && - mouse_x <= GetBarRect().right && - mouse_y >= GetBarRect().top && - mouse_y <= GetBarRect().bottom) + if (GetBarRect().PointInside(mouse)) { m_BarPressed = true; - m_BarPressedAtX = mouse_x; - m_BarPressedAtY = mouse_y; + m_BarPressedAtPos = mouse; m_PosWhenPressed = m_Pos; } else // if button-minus is pressed - if (HoveringButtonMinus(mouse_x, mouse_y)) + if (m_ButtonMinusHovered) { + m_ButtonMinusPressed = true; ScrollMinus(); } else // if button-plus is pressed - if (HoveringButtonPlus(mouse_x, mouse_y)) + if (m_ButtonPlusHovered) { + m_ButtonPlusPressed = true; ScrollPlus(); } - } + else + // Pressing the background of the bar, to scroll + // notice the if-sentence alone does not admit that, + // it must be after the above if/elses + { + if (GetOuterRect().PointInside(mouse)) + { + // Scroll plus or minus a lot, this might change, it doesn't + // have to be fancy though. + if (mouse.y < GetBarRect().top) + ScrollMinusPlenty(); + else + ScrollPlusPlenty(); + + // Simulate mouse movement to see if bar now is hovered + HandleMessage(SGUIMessage(GUIM_MOUSE_MOTION)); + } + } + } break; + + case GUIM_MOUSE_RELEASE_LEFT: + m_ButtonMinusPressed = false; + m_ButtonPlusPressed = false; break; default: - return false; + break; } - - return true; } diff --git a/source/gui/IGUIScrollBar.h b/source/gui/IGUIScrollBar.h index fb87481384..cddb88f78f 100755 --- a/source/gui/IGUIScrollBar.h +++ b/source/gui/IGUIScrollBar.h @@ -86,13 +86,18 @@ struct SGUIScrollBarStyle CStr m_SpriteButtonTop; CStr m_SpriteButtonTopPressed; CStr m_SpriteButtonTopDisabled; + CStr m_SpriteButtonTopOver; CStr m_SpriteButtonBottom; CStr m_SpriteButtonBottomPressed; CStr m_SpriteButtonBottomDisabled; + CStr m_SpriteButtonBottomOver; - CStr m_SpriteScrollBackHorizontal; - CStr m_SpriteScrollBarHorizontal; + CStr m_SpriteBarVertical; + CStr m_SpriteBarVerticalOver; + CStr m_SpriteBarVerticalPressed; + + CStr m_SpriteBackVertical; //@} //-------------------------------------------------------- @@ -108,8 +113,8 @@ struct SGUIScrollBarStyle CStr m_SpriteButtonRightPressed; CStr m_SpriteButtonRightDisabled; - CStr m_SpriteScrollBackVertical; - CStr m_SpriteScrollBarVertical; + CStr m_SpriteBackHorizontal; + CStr m_SpriteBarHorizontal; //@} }; @@ -151,12 +156,12 @@ public: * @return true if messages handled the scroll-bar some. False if * the message should be processed by the object. */ - virtual bool HandleMessage(const SGUIMessage &Message)=0; + virtual void HandleMessage(const SGUIMessage &Message)=0; /** * Set m_Pos with mouse_x/y input, i.e. when draggin. */ - virtual void SetPosFromMousePos(int _x, int _y)=0; + virtual void SetPosFromMousePos(const CPos &mouse)=0; /** * Hovering the scroll minus button @@ -165,7 +170,7 @@ public: * @param m_y mouse y * @return True if mouse positions are hovering the button */ - virtual bool HoveringButtonMinus(int m_x, int m_y) { return false; } + virtual bool HoveringButtonMinus(const CPos &mouse) { return false; } /** * Hovering the scroll plus button @@ -174,17 +179,32 @@ public: * @param m_y mouse y * @return True if mouse positions are hovering the button */ - virtual bool HoveringButtonPlus(int m_x, int m_y) { return false; } + virtual bool HoveringButtonPlus(const CPos &mouse) { return false; } + + /** + * Get scroll-position + */ + int GetPos() const { return m_Pos; } /** * Scroll towards 1.0 one step */ - virtual void ScrollPlus() { m_Pos += 0.1f; UpdatePosBoundaries(); } + virtual void ScrollPlus() { m_Pos += 30; UpdatePosBoundaries(); } /** * Scroll towards 0.0 one step */ - virtual void ScrollMinus() { m_Pos -= 0.1f; UpdatePosBoundaries(); } + virtual void ScrollMinus() { m_Pos -= 30; UpdatePosBoundaries(); } + + /** + * Scroll towards 1.0 one step + */ + virtual void ScrollPlusPlenty() { m_Pos += 90; UpdatePosBoundaries(); } + + /** + * Scroll towards 0.0 one step + */ + virtual void ScrollMinusPlenty() { m_Pos -= 90; UpdatePosBoundaries(); } /** * Set host object, must be done almost at creation of scroll bar. @@ -192,6 +212,18 @@ public: */ void SetHostObject(IGUIScrollBarOwner * pOwner) { m_pHostObject = pOwner; } + /** + * Get GUI pointer + * @return CGUI pointer + */ + CGUI *GetGUI() const; + + /** + * Set GUI pointer + * @param pGUI pointer to CGUI object. + */ + void SetGUI(CGUI *pGUI) { m_pGUI = pGUI; } + /** * Set Width * @param width Width @@ -202,25 +234,37 @@ public: * Set X Position * @param x Position in this axis */ - void SetX(const int &x) {m_X = x; } + void SetX(const int &x) { m_X = x; } /** * Set Y Position * @param y Position in this axis */ - void SetY(const int &y) {m_Y = y; } + void SetY(const int &y) { m_Y = y; } /** * Set Z Position * @param z Position in this axis */ - void SetZ(const float &z) {m_Z = z; } + void SetZ(const float &z) { m_Z = z; } /** * Set Length of scroll bar * @param length Length */ - void SetLength(const float &length) {m_Length = length; } + void SetLength(const int &length) { m_Length = length; } + + /** + * Set content length + * @param range Maximum scrollable range + */ + void SetScrollRange(const int &range) { m_ScrollRange = max(range,1); SetupBarSize(); } + + /** + * Set space that is visible in the scrollable control. + * @param space Visible area in the scrollable control. + */ + void SetScrollSpace(const int &space) { m_ScrollSpace = space; SetupBarSize(); } /** * Set bar pressed @@ -228,23 +272,42 @@ public: */ void SetBarPressed(const bool &b) { m_BarPressed = b; } + /** + * Set use edge buttons + * @param b True if edge buttons should be used + */ + void SetUseEdgeButtons(const bool &b) { m_UseEdgeButtons = b; } + /** * Set Scroll bar style string * @param style String with scroll bar style reference name */ void SetScrollBarStyle(const CStr &style) { m_ScrollBarStyle = style; } -protected: - /** - * Get the rectangle of the actual BAR. not the whole scroll-bar. - */ - virtual CRect GetBarRect() const = 0; - /** * Get style used by the scrollbar * @return Scroll bar style struct. */ - const SGUIScrollBarStyle & GetStyle() const; + const SGUIScrollBarStyle * GetStyle() const; + +protected: + /** + * Sets up bar size + */ + void SetupBarSize(); + + /** + * Get the rectangle of the actual BAR. not the whole scroll-bar. + * @return Rectangle, CRect + */ + virtual CRect GetBarRect() const = 0; + + /** + * Get the rectangle of the outline of the scrollbar, every component of the + * scroll-bar should be inside this area. + * @return Rectangle, CRect + */ + virtual CRect GetOuterRect() const = 0; /** * Call every time m_Pos has been updated. @@ -258,10 +321,16 @@ protected: //-------------------------------------------------------- //@{ + /** + * True if you want edge buttons, i.e. buttons that can be pressed in order + * to scroll. + */ + bool m_UseEdgeButtons; + /** * Width of the scroll bar */ - int16 m_Width; + int m_Width; /** * Absolute X Position @@ -283,6 +352,16 @@ protected: */ int m_Length; + /** + * Content that can be scrolled, in pixels + */ + int m_ScrollRange; + + /** + * Content that can be viewed at a time, in pixels + */ + int m_ScrollSpace; + /** * Use input from the scroll-wheel? True or false. */ @@ -303,10 +382,15 @@ protected: */ IGUIScrollBarOwner *m_pHostObject; + /** + * Reference to CGUI object, these cannot work stand-alone + */ + CGUI *m_pGUI; + /** * Mouse position when bar was pressed */ - int m_BarPressedAtX, m_BarPressedAtY; + CPos m_BarPressedAtPos; //@} //-------------------------------------------------------- @@ -320,10 +404,26 @@ protected: bool m_BarPressed; /** - * Position of scroll bar, 0 means scrolled all the way to one side... 1 means - * scrolled all the way to the other side. + * Bar being hovered or not */ - float m_Pos; + bool m_BarHovered; + + /** + * Scroll buttons hovered + */ + bool m_ButtonMinusHovered, m_ButtonPlusHovered; + + /** + * Scroll buttons pressed + */ + bool m_ButtonMinusPressed, m_ButtonPlusPressed; + + /** + * Position of scroll bar, 0 means scrolled all the way to one side. + * It is meassured in pixels, it is up to the host to make it actually + * apply in pixels. + */ + int m_Pos; /** * Position from 0.f to 1.f it had when the bar was pressed. diff --git a/source/gui/IGUIScrollBarOwner.cpp b/source/gui/IGUIScrollBarOwner.cpp index 89cc9bf1bf..0e5031d117 100755 --- a/source/gui/IGUIScrollBarOwner.cpp +++ b/source/gui/IGUIScrollBarOwner.cpp @@ -40,24 +40,31 @@ void IGUIScrollBarOwner::ResetStates() void IGUIScrollBarOwner::AddScrollBar(IGUIScrollBar * scrollbar) { scrollbar->SetHostObject(this); + scrollbar->SetGUI(GetGUI()); m_ScrollBars.push_back(scrollbar); } - -const SGUIScrollBarStyle & IGUIScrollBarOwner::GetScrollBarStyle(const CStr &style) const +/* +void SetGUI(CGUI * const &pGUI) +{ + m_pGUI = pGUI; + scrollbar->SetGUI(m_pGUI); +} +*/ +const SGUIScrollBarStyle * IGUIScrollBarOwner::GetScrollBarStyle(const CStr &style) const { if (!GetGUI()) { // TODO Gee: Output in log - return SGUIScrollBarStyle(); + return NULL; } if (GetGUI()->m_ScrollBarStyles.count(style) == 0) { // TODO Gee: Output in log - return SGUIScrollBarStyle(); + return NULL; } - return GetGUI()->m_ScrollBarStyles.find(style)->second; + return &GetGUI()->m_ScrollBarStyles.find(style)->second; } void IGUIScrollBarOwner::HandleMessage(const SGUIMessage &Message) diff --git a/source/gui/IGUIScrollBarOwner.h b/source/gui/IGUIScrollBarOwner.h index 141dd4c4f0..b14769e722 100755 --- a/source/gui/IGUIScrollBarOwner.h +++ b/source/gui/IGUIScrollBarOwner.h @@ -46,6 +46,8 @@ struct SGUIScrollBarStyle; */ class IGUIScrollBarOwner : virtual public IGUIObject { + friend class IGUIScrollBar; + public: IGUIScrollBarOwner(); virtual ~IGUIScrollBarOwner(); @@ -65,7 +67,7 @@ public: /** * Interface for the m_ScrollBar to use. */ - virtual const SGUIScrollBarStyle & GetScrollBarStyle(const CStr &style) const; + virtual const SGUIScrollBarStyle *GetScrollBarStyle(const CStr &style) const; /** * Add a scroll-bar diff --git a/source/gui/IGUISettingsObject.cpp b/source/gui/IGUISettingsObject.cpp deleted file mode 100755 index bdec22f724..0000000000 --- a/source/gui/IGUISettingsObject.cpp +++ /dev/null @@ -1,11 +0,0 @@ -/* -IGUISettingsObject -by Gustav Larsson -gee@pyro.nu -*/ - -//#include "stdafx.h" -#include "GUI.h" - -using namespace std; - diff --git a/source/gui/IGUISettingsObject.h b/source/gui/IGUISettingsObject.h deleted file mode 100755 index a27e7d18ac..0000000000 --- a/source/gui/IGUISettingsObject.h +++ /dev/null @@ -1,146 +0,0 @@ -/* -GUI Object Base - Setting Extension -by Gustav Larsson -gee@pyro.nu - ---Overview-- - - Generic object that stores a struct with settings - ---Usage-- - - If an object wants settings with a standard, - it will use this as a middle step instead of being - directly derived from IGUIObject - ---Examples-- - - instead of: - - class CButton : public IGUIObject - - you go: - - class CButton : public IGUISettingsObject - - and SButtonSettings will be included as m_Settings with - all gets and sets set up - ---More info-- - - Check GUI.h - -*/ - -#ifndef IGUISettingsObject_H -#define IGUISettingsObject_H - -//-------------------------------------------------------- -// Includes / Compiler directives -//-------------------------------------------------------- -#include "GUI.h" - -//-------------------------------------------------------- -// Macros -//-------------------------------------------------------- - -//-------------------------------------------------------- -// Types -//-------------------------------------------------------- - -//-------------------------------------------------------- -// Error declarations -//-------------------------------------------------------- - -//-------------------------------------------------------- -// Declarations -//-------------------------------------------------------- - -/** - * @author Gustav Larsson - * - * Appends more settings to the IGUIObject. - * Can be used with multiple inheritance. - * - * @see IGUIObject - */ -template -class IGUISettingsObject : virtual public IGUIObject -{ -public: - IGUISettingsObject() {} - virtual ~IGUISettingsObject() {} - - /** - * Get Offsets, important to include so it returns this - * m_Offsets and not IGUIObject::m_SettingsInfo - * - * @return Settings infos - */ - virtual map_Settings GetSettingsInfo() const { return m_SettingsInfo; } - - /** - * @return Returns a copy of m_Settings - */ - SETTINGS GetSettings() const { return m_Settings; } - - /// Sets settings - void SetSettings(const SETTINGS &Set) - { - m_Settings = Set; - - //CheckSettingsValidity(); - // Since that function out-commented above really - // does just update the base settings, we'll call - // the message immediately instead - try - { - HandleMessage(GUIM_SETTINGS_UPDATED); - } - catch (...) { } - } - -protected: - /** - * You input the setting struct you want, and it will return a pointer to - * the struct. - * - * @param SettingsStruct tells us which pointer to return - */ - virtual void *GetStructPointer(const EGUISettingsStruct &SettingsStruct) const - { - switch (SettingsStruct) - { - case GUISS_BASE: - return (void*)&m_BaseSettings; - - case GUISS_EXTENDED: - return (void*)&m_Settings; - - default: - // TODO Gee: Report error - return NULL; - } - } - - /// Settings struct - SETTINGS m_Settings; - - /** - * Offset database\n - * tells us where a variable by a string name is - * located hardcoded, in order to acquire a pointer - * for that variable... Say "frozen" gives - * the offset from IGUIObject to m_Frozen. - * - * note! _NOT_ from SGUIBaseSettings to m_Frozen! - * - * Note that it's imperative that this m_SettingsInfo includes - * all offsets of m_BaseSettings too, because when - * using this class, this m_SettingsInfo will be the only - * one used. - */ - static map_Settings m_SettingsInfo; -}; - -#endif diff --git a/source/gui/IGUITextOwner.cpp b/source/gui/IGUITextOwner.cpp new file mode 100755 index 0000000000..56c0028c5e --- /dev/null +++ b/source/gui/IGUITextOwner.cpp @@ -0,0 +1,73 @@ +/* +IGUITextOwner +by Gustav Larsson +gee@pyro.nu +*/ + +//#include "stdafx.h" +#include "GUI.h" + +using namespace std; + +//------------------------------------------------------------------- +// Constructor / Destructor +//------------------------------------------------------------------- +IGUITextOwner::IGUITextOwner() +{ +} + +IGUITextOwner::~IGUITextOwner() +{ + // Delete scroll-bars + vector::iterator it; + for (it=m_GeneratedTexts.begin(); it!=m_GeneratedTexts.end(); ++it) + { + delete *it; + } +} + +void IGUITextOwner::AddText(SGUIText * text) +{ + m_GeneratedTexts.push_back(text); +} + +void IGUITextOwner::HandleMessage(const SGUIMessage &Message) +{ + switch (Message.type) + { + case GUIM_SETTINGS_UPDATED: + // Everything that can change the visual appearance. + // it is assumed that the text of the object will be dependent on + // these. But that is not certain, but one will have to manually + // change it and disregard this function. + if (Message.value == CStr("size") || Message.value == CStr("z") || + Message.value == CStr("absolute") || Message.value == CStr("caption") || + Message.value == CStr("font") || Message.value == CStr("textcolor")) + { + SetupText(); + } + break; + + case GUIM_LOAD: + SetupText(); + break; + + default: + break; + } +} + +void IGUITextOwner::Draw(const int &index, const CColor &color, const CPos &pos, + const float &z, const CRect &clipping) +{ + if (index < 0 && index >= m_GeneratedTexts.size()) + { + // TODO Gee: Warning + return; + } + + if (GetGUI()) + { + GetGUI()->DrawText(*m_GeneratedTexts[index], color, pos, z); + } +} diff --git a/source/gui/IGUITextOwner.h b/source/gui/IGUITextOwner.h new file mode 100755 index 0000000000..c678bd1751 --- /dev/null +++ b/source/gui/IGUITextOwner.h @@ -0,0 +1,88 @@ +/* +GUI Object Base - Text Owner +by Gustav Larsson +gee@pyro.nu + +--Overview-- + + Interface class that enhance the IGUIObject with + cached CGUIStrings. This class is not at all needed, + and many controls that will use CGUIStrings might + not use this, but does help for regular usage such + as a text-box, a button, a radio button etc. + +--More info-- + + Check GUI.h + +*/ + +#ifndef IGUITextOwner_H +#define IGUITextOwner_H + +//-------------------------------------------------------- +// Includes / Compiler directives +//-------------------------------------------------------- +#include "GUI.h" + +//-------------------------------------------------------- +// Macros +//-------------------------------------------------------- + +//-------------------------------------------------------- +// Types +//-------------------------------------------------------- + +//-------------------------------------------------------- +// Declarations +//-------------------------------------------------------- + +/** + * @author Gustav Larsson + * + * Framework for handling Output text. + * + * @see IGUIObject + */ +class IGUITextOwner : virtual public IGUIObject +{ +public: + IGUITextOwner(); + virtual ~IGUITextOwner(); + + /** + * Adds a text object. + */ + void AddText(SGUIText * text); + + /** + * @see IGUIObject#HandleMessage() + */ + virtual void HandleMessage(const SGUIMessage &Message); + + /** + * Draws the Text. + * + * @param index Index value of text. Mostly this will be 0 + * @param pos Position + * @param z Z value + * @param clipping Clipping rectangle, don't even add a paramter + * to get no clipping. + */ + virtual void Draw(const int &index, const CColor &color, const CPos &pos, + const float &z, const CRect &clipping = CRect()); + +protected: + + /** + * Setup texts. Functions that sets up all texts when changes have been made. + */ + virtual void SetupText()=0; + + /** + * Texts that are generated and ready to be rendred. + */ + std::vector m_GeneratedTexts; +}; + +#endif