diff --git a/source/gui/CButton.cpp b/source/gui/CButton.cpp index 39c1e84eae..d6921ac88e 100755 --- a/source/gui/CButton.cpp +++ b/source/gui/CButton.cpp @@ -23,6 +23,8 @@ CButton::CButton() AddSetting(GUIST_CStr, "sprite-over"); AddSetting(GUIST_CStr, "sprite-pressed"); AddSetting(GUIST_CStr, "sprite-disabled"); + AddSetting(GUIST_EAlign, "text-align"); + AddSetting(GUIST_EVAlign, "text-valign"); AddSetting(GUIST_CColor, "textcolor"); AddSetting(GUIST_CColor, "textcolor-over"); AddSetting(GUIST_CColor, "textcolor-pressed"); @@ -55,8 +57,45 @@ void CButton::SetupText() *m_GeneratedTexts[0] = GetGUI()->GenerateText(caption, font, m_CachedActualSize.GetWidth(), 0, this); // Set position of text - //m_TextPos = m_CachedActualSize.CenterPoint() - m_GeneratedTexts[0]->m_Size/2; + + // Check which alignment to use! + EAlign align; + EVAlign valign; + GUI::GetSetting(this, "text-align", align); + GUI::GetSetting(this, "text-valign", valign); + m_TextPos = m_CachedActualSize.TopLeft(); + + switch (align) + { + case EAlign_Left: + m_TextPos.x = m_CachedActualSize.left; + break; + case EAlign_Center: + m_TextPos.x = m_CachedActualSize.CenterPoint().x - m_GeneratedTexts[0]->m_Size.cx/2; + break; + case EAlign_Right: + m_TextPos.x = m_CachedActualSize.right - m_GeneratedTexts[0]->m_Size.cx; + break; + default: + break; + } + + switch (valign) + { + case EVAlign_Top: + m_TextPos.y = m_CachedActualSize.top; + break; + case EVAlign_Center: + m_TextPos.y = m_CachedActualSize.CenterPoint().y - m_GeneratedTexts[0]->m_Size.cy/2; + break; + case EVAlign_Bottom: + m_TextPos.y = m_CachedActualSize.bottom - m_GeneratedTexts[0]->m_Size.cy; + break; + default: + break; + } + } void CButton::HandleMessage(const SGUIMessage &Message) diff --git a/source/gui/CButton.h b/source/gui/CButton.h index 9067dee0c3..1fec4f21ac 100755 --- a/source/gui/CButton.h +++ b/source/gui/CButton.h @@ -39,7 +39,6 @@ gee@pyro.nu * Button * * @see IGUIObject - * @see IGUISettingsObject * @see IGUIButtonBehavior */ class CButton : public IGUIButtonBehavior, public IGUITextOwner diff --git a/source/gui/CCheckBox.cpp b/source/gui/CCheckBox.cpp index 3ad8b94132..7cd53d17a5 100755 --- a/source/gui/CCheckBox.cpp +++ b/source/gui/CCheckBox.cpp @@ -31,7 +31,7 @@ CCheckBox::CCheckBox() CColor m_TextColorDisabled; CColor m_TextColorOver; CColor m_TextColorPressed; - EValign m_TextValign; + EVAlign m_TextValign; CStr m_ToolTip; CStr m_ToolTipStyle; */ diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 94f2d3a51d..034c816858 100755 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -10,6 +10,7 @@ gee@pyro.nu // Types - when including them into the engine. #include "CButton.h" +#include "CImage.h" #include "CText.h" #include "CCheckBox.h" #include "CRadioButton.h" @@ -81,11 +82,6 @@ int CGUI::HandleEvent(const SDL_Event* ev) SGUIMessage(GUIM_MOUSE_MOTION)); } - // TODO Gee: temp-stuff -// char buf[30]; -// sprintf(buf, "type = %d", ev->type); - //TEMPmessage = buf; - // Update m_MouseButtons. (BUTTONUP is handled later.) if (ev->type == SDL_MOUSEBUTTONDOWN) { @@ -247,8 +243,7 @@ IGUIObject *CGUI::ConstructObject(const CStr& str) return (*m_ObjectTypes[str])(); else { - debug_warn("CGUI::ConstructObject error"); - // TODO Gee: Report in log + // Error reporting will be handled with the NULL return. return NULL; } } @@ -260,6 +255,7 @@ void CGUI::Initialize() // Prometheus though will have all the object types inserted from here. AddObjectType("empty", &CGUIDummyObject::ConstructObject); AddObjectType("button", &CButton::ConstructObject); + AddObjectType("image", &CImage::ConstructObject); AddObjectType("text", &CText::ConstructObject); AddObjectType("checkbox", &CCheckBox::ConstructObject); AddObjectType("radiobutton", &CRadioButton::ConstructObject); @@ -422,19 +418,41 @@ void CGUI::DrawSprite(const CStr& SpriteName, // Get the screen position/size of a single tiling of the texture CRect TexSize = cit->m_TextureSize.GetClientArea(real); - float TexLeft = (float)(TexSize.left - real.left) / (float)TexSize.GetWidth(); - float TexRight = TexLeft + (float)real.GetWidth() / (float)TexSize.GetWidth(); + // Actual texture coordinates we'll send to OGL. + CRect TexCoords; + + TexCoords.left = (TexSize.left - real.left) / TexSize.GetWidth(); + TexCoords.right = TexCoords.left + real.GetWidth() / TexSize.GetWidth(); // 'Bottom' is actually the top in screen-space (I think), // because the GUI puts (0,0) at the top-left - float TexBottom = (float)(TexSize.bottom - real.bottom) / (float)TexSize.GetHeight(); - float TexTop = TexBottom + (float)real.GetHeight() / (float)TexSize.GetHeight(); + TexCoords.bottom = (TexSize.bottom - real.bottom) / TexSize.GetHeight(); + TexCoords.top = TexCoords.bottom + real.GetHeight() / TexSize.GetHeight(); + + if (cit->m_TexturePlacementInFile != CRect()) + { + // Save the width/height, because we'll change the values one at a time and need + // to be able to use the unchanged width/height + float width = TexCoords.GetWidth(), + height = TexCoords.GetHeight(); + + // Get texture width/height + int t_w, t_h; + tex_info(cit->m_Texture, &t_w, &t_h, NULL, NULL, NULL); + + // notice left done after right, so that left is still unchanged, that is important. + TexCoords.right = TexCoords.left + width * cit->m_TexturePlacementInFile.right/(float)t_w; + TexCoords.left += width * cit->m_TexturePlacementInFile.left/(float)t_w; + + TexCoords.bottom = TexCoords.top + height * cit->m_TexturePlacementInFile.bottom/(float)t_h; + TexCoords.top += height * cit->m_TexturePlacementInFile.top/(float)t_h; + } glBegin(GL_QUADS); - glTexCoord2f(TexRight, TexBottom); glVertex3f((float)real.right, (float)real.bottom, cit->m_DeltaZ); - glTexCoord2f(TexLeft, TexBottom); glVertex3f((float)real.left, (float)real.bottom, cit->m_DeltaZ); - glTexCoord2f(TexLeft, TexTop); glVertex3f((float)real.left, (float)real.top, cit->m_DeltaZ); - glTexCoord2f(TexRight, TexTop); glVertex3f((float)real.right, (float)real.top, cit->m_DeltaZ); + glTexCoord2f(TexCoords.right, TexCoords.bottom); glVertex3f(real.right, real.bottom, cit->m_DeltaZ); + glTexCoord2f(TexCoords.left, TexCoords.bottom); glVertex3f(real.left, real.bottom, cit->m_DeltaZ); + glTexCoord2f(TexCoords.left, TexCoords.top); glVertex3f(real.left, real.top, cit->m_DeltaZ); + glTexCoord2f(TexCoords.right, TexCoords.top); glVertex3f(real.right, real.top, cit->m_DeltaZ); glEnd(); glDisable(GL_TEXTURE_2D); @@ -607,8 +625,6 @@ SGUIText CGUI::GenerateText(const CGUIString &string, // Easier to read. bool WordWrapping = (Width != 0); - size_t TEMP = string.m_Words.size(); - // Go through string word by word for (int i=0; i<(int)string.m_Words.size()-1 && !done; ++i) { @@ -634,9 +650,6 @@ SGUIText CGUI::GenerateText(const CGUIString &string, // Loop left/right for (int j=0; j<2; ++j) { - // TEMP - int TEMPsize = Feedback.m_Images[j].size(); - for (vector::const_iterator it = Feedback.m_Images[j].begin(); it != Feedback.m_Images[j].end(); ++it) @@ -1496,6 +1509,16 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite else image.m_TextureSize = ca; } else + if (attr_name == "real-texture-placement") + { + CRect rect; + if (!GUI::ParseString(attr_value, rect)) + { + ReportParseError("TODO"); + } + else image.m_TexturePlacementInFile = rect; + } + else if (attr_name == "z-level") { int z_level; diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index a0450d57a6..608e07287f 100755 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -81,9 +81,6 @@ public: CGUI(); ~CGUI(); - // TODO Gee: (MEGA) Extremely temporary. - std::string TEMPmessage; - /** * Initializes the GUI, needs to be called before the GUI is used */ diff --git a/source/gui/CGUISprite.h b/source/gui/CGUISprite.h index 7d8fe4acdf..831a99d475 100755 --- a/source/gui/CGUISprite.h +++ b/source/gui/CGUISprite.h @@ -53,7 +53,7 @@ gee@pyro.nu */ struct SGUIImage { - SGUIImage() : m_Texture(0), m_Border(false), m_DeltaZ(0.f) {} + SGUIImage() : m_Texture(0), m_Border(false), m_DeltaZ(0.f), m_TexturePlacementInFile() {} ~SGUIImage() { if (m_Texture) tex_free(m_Texture); @@ -69,6 +69,7 @@ struct SGUIImage C(Size); C(TextureSize); C(BackColor); C(BorderColor); C(Border); C(DeltaZ); + C(TexturePlacementInFile); #undef C // 'Load' the texture (but don't do any work because it's cached) if (m_Texture) @@ -84,6 +85,11 @@ struct SGUIImage // Texture placement CClientArea m_TextureSize; + // Because OpenGL wants textures in squares with a power of 2 (64x64, 256x256) + // it's sometimes tediuos to adjust this. So this value simulates which area + // is the real texture + CRect m_TexturePlacementInFile; + // Color CColor m_BackColor; CColor m_BorderColor; diff --git a/source/gui/CText.cpp b/source/gui/CText.cpp index a3bcef2e84..4bd1355db9 100755 --- a/source/gui/CText.cpp +++ b/source/gui/CText.cpp @@ -100,6 +100,7 @@ void CText::HandleMessage(const SGUIMessage &Message) GUI::GetSetting(this, "scrollbar", scrollbar); // Update scroll-bar + // TODO Gee: (2004-09-01) Is this really updated each time it should? if (scrollbar && (Message.value == CStr("size") || Message.value == CStr("z") || Message.value == CStr("absolute"))) @@ -143,10 +144,6 @@ void CText::HandleMessage(const SGUIMessage &Message) void CText::Draw() { - ////////// Gee: janwas, this is just temp to see it - glDisable(GL_TEXTURE_2D); - ////////// - float bz = GetBufferedZ(); // First call draw on ScrollBarOwner diff --git a/source/gui/CText.h b/source/gui/CText.h index 4979a1dcf4..f1067b58ad 100755 --- a/source/gui/CText.h +++ b/source/gui/CText.h @@ -42,7 +42,6 @@ class IGUIScrollBar; * Text field that just displays static text. * * @see IGUIObject - * @see IGUISettingsObject */ class CText : public IGUIScrollBarOwner, public IGUITextOwner { diff --git a/source/gui/GUIbase.cpp b/source/gui/GUIbase.cpp index 8b250b7875..3f7de6add9 100755 --- a/source/gui/GUIbase.cpp +++ b/source/gui/GUIbase.cpp @@ -11,6 +11,7 @@ gee@pyro.nu //-------------------------------------------------------- // Error definitions //-------------------------------------------------------- +// TODO Gee: (2004-09-01) Keeper? The PS_NAME_ABIGUITY for instance doesn't let the user know which objects. DEFINE_ERROR(PS_NAME_TAKEN, "Reference name is taken"); DEFINE_ERROR(PS_OBJECT_FAIL, "Object provided is null"); DEFINE_ERROR(PS_SETTING_FAIL, "Setting does not exist"); diff --git a/source/gui/GUIbase.h b/source/gui/GUIbase.h index 3a11c5b63e..da1912dcff 100755 --- a/source/gui/GUIbase.h +++ b/source/gui/GUIbase.h @@ -128,23 +128,14 @@ enum EGUISettingsStruct GUISS_EXTENDED }; +// Text alignments +enum EAlign { EAlign_Left, EAlign_Right, EAlign_Center }; +enum EVAlign { EVAlign_Top, EVAlign_Bottom, EVAlign_Center }; + // Typedefs typedef std::map map_pObjects; typedef std::vector vector_pObjects; -// Smaller structs that don't deserve their own files :) - -// Icon, you create them in the XML file with root element -// you use them in text owned by different objects... Such as CText. -struct SGUIIcon -{ - // Texture name of icon - CStr m_TextureName; - - // Size - CSize m_Size; -}; - //-------------------------------------------------------- // Error declarations //-------------------------------------------------------- diff --git a/source/gui/GUItext.cpp b/source/gui/GUItext.cpp index 61649ae066..7a4cda800a 100755 --- a/source/gui/GUItext.cpp +++ b/source/gui/GUItext.cpp @@ -69,7 +69,7 @@ void CGUIString::GenerateTextCall(SFeedback &Feedback, // it's in the end of one word, and the icon // should really belong to the beginning of the next one - if (_to == to) + if (_to == to && to >= 1) { if (GetRawString()[to-1] == ' ' || GetRawString()[to-1] == '-' || @@ -203,7 +203,7 @@ void CGUIString::GenerateTextCall(SFeedback &Feedback, Feedback.m_Size.cx += size.cx; Feedback.m_Size.cy = max(Feedback.m_Size.cy, size.cy); - // These are also needed later + // These are also ne eded later TextCall.m_Size = size; if (TextCall.m_String.Length() >= 1) diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index 8d9b2ea287..a8a07371a3 100755 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -156,6 +156,40 @@ bool __ParseString(const CStr& Value, CSize &Output) return true; } +template <> +bool __ParseString(const CStr &Value, EAlign &Output) +{ + if (Value == (CStr)"left") + Output = EAlign_Left; + else + if (Value == (CStr)"center") + Output = EAlign_Center; + else + if (Value == (CStr)"right") + Output = EAlign_Right; + else + return false; + + return true; +} + +template <> +bool __ParseString(const CStr &Value, EVAlign &Output) +{ + if (Value == (CStr)"top") + Output = EVAlign_Top; + else + if (Value == (CStr)"center") + Output = EVAlign_Center; + else + if (Value == (CStr)"bottom") + Output = EVAlign_Bottom; + else + return false; + + return true; +} + template <> bool __ParseString(const CStr& Value, CGUIString &Output) { @@ -179,16 +213,16 @@ CClientArea::CClientArea(const CStr& Value) CRect CClientArea::GetClientArea(const CRect &parent) const { // If it's a 0 0 100% 100% we need no calculations - if (percent == CRect(0,0,100,100) && pixel == CRect(0,0,0,0)) + if (percent == CRect(0.f,0.f,100.f,100.f) && pixel == CRect(0.f,0.f,0.f,0.f)) return parent; CRect client; // This should probably be cached and not calculated all the time for every object. - client.left = parent.left + int(float((parent.right-parent.left)*percent.left)/100.f) + pixel.left; - client.top = parent.top + int(float((parent.bottom-parent.top)*percent.top)/100.f) + pixel.top; - client.right = parent.left + int(float((parent.right-parent.left)*percent.right)/100.f) + pixel.right; - client.bottom = parent.top + int(float((parent.bottom-parent.top)*percent.bottom)/100.f) + pixel.bottom; + client.left = parent.left + (parent.right-parent.left)*percent.left/100.f + pixel.left; + client.top = parent.top + (parent.bottom-parent.top)*percent.top/100.f + pixel.top; + client.right = parent.left + (parent.right-parent.left)*percent.right/100.f + pixel.right; + client.bottom = parent.top + (parent.bottom-parent.top)*percent.bottom/100.f + pixel.bottom; return client; } @@ -265,7 +299,9 @@ bool CClientArea::SetClientArea(const CStr& Value) // 4 arguments = INVALID // Default to 0 - int values[4][2] = {{0,0},{0,0},{0,0},{0,0}}; + //int values[4][2] = {{0,0},{0,0},{0,0},{0,0}}; + int i_values[4] = {0,0,0,0}; + float f_values[4] = {0.f, 0.f, 0.f, 0.f}; for (int v=0; v<4; ++v) { @@ -274,20 +310,20 @@ bool CClientArea::SetClientArea(const CStr& Value) string str; line.GetArgString(arg_start[v], str); - if (!line.GetArgInt(arg_start[v], values[v][1])) + if (!line.GetArgInt(arg_start[v], i_values[v])) return false; } else if (arg_count[v] == 2) { - if (!line.GetArgInt(arg_start[v], values[v][0])) + if (!line.GetArgFloat(arg_start[v], f_values[v])) return false; } else if (arg_count[v] == 3) { - if (!line.GetArgInt(arg_start[v], values[v][0]) || - !line.GetArgInt(arg_start[v]+2, values[v][1])) + if (!line.GetArgFloat(arg_start[v], f_values[v]) || + !line.GetArgInt(arg_start[v]+2, i_values[v])) return false; } @@ -295,14 +331,14 @@ bool CClientArea::SetClientArea(const CStr& Value) } // Now store the values[][] in the right place - pixel.left = values[0][1]; - pixel.top = values[1][1]; - pixel.right = values[2][1]; - pixel.bottom = values[3][1]; - percent.left = values[0][0]; - percent.top = values[1][0]; - percent.right = values[2][0]; - percent.bottom = values[3][0]; + pixel.left = i_values[0]; + pixel.top = i_values[1]; + pixel.right = i_values[2]; + pixel.bottom = i_values[3]; + percent.left = f_values[0]; + percent.top = f_values[1]; + percent.right = f_values[2]; + percent.bottom = f_values[3]; return true; } diff --git a/source/gui/GUIutil.h b/source/gui/GUIutil.h index ca2466b366..bbe230a203 100755 --- a/source/gui/GUIutil.h +++ b/source/gui/GUIutil.h @@ -57,9 +57,28 @@ bool __ParseString(const CStr& Value, CColor &Output); template <> bool __ParseString(const CStr& Value, CSize &Output); +template <> +bool __ParseString(const CStr& Value, EAlign &Output); + +template <> +bool __ParseString(const CStr& Value, EVAlign &Output); + template <> bool __ParseString(const CStr& Value, CGUIString &Output); + +// Icon, you create them in the XML file with root element +// you use them in text owned by different objects... Such as CText. +struct SGUIIcon +{ + // Texture name of icon + CStr m_TextureName; + + // Size + CSize m_Size; +}; + + /** * @author Gustav Larsson * @@ -77,7 +96,7 @@ public: /// Pixel modifiers CRect pixel; - /// Percent modifiers (I'll let this be integers, I don't think a greater precision is needed) + /// Percent modifiers CRect percent; /** @@ -88,9 +107,8 @@ public: /** * The ClientArea can be set from a string looking like: * - * @code * "0 0 100% 100%" - * "50%-10 50%-10 50%+10 50%+10" @endcode + * "50%-10 50%-10 50%+10 50%+10" * * i.e. First percent modifier, then + or - and the pixel modifier. * Although you can use just the percent or the pixel modifier. Notice diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index ee115bd81b..de8896d751 100755 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -71,6 +71,8 @@ IGUIObject::~IGUIObject() TYPE(CClientArea); TYPE(CGUIString); TYPE(CStr); + TYPE(EAlign); + TYPE(EVAlign); default: assert(!"Invalid setting type"); } @@ -169,11 +171,11 @@ void IGUIObject::AddSetting(const EGUISettingType &Type, const CStr& Name) CASE_TYPE(CStr) CASE_TYPE(CColor) CASE_TYPE(CGUIString) + CASE_TYPE(EAlign) + CASE_TYPE(EVAlign) default: - debug_warn("IGUIObject::AddSetting failed"); - // TODO Gee: Report in log, type is not recognized. This should be an assert, not in log - // because it's strictly hardcoded error + debug_warn("IGUIObject::AddSetting failed, type not recognized!"); break; } } @@ -262,6 +264,8 @@ void IGUIObject::SetSetting(const CStr& Setting, const CStr& Value) ADD_TYPE(CColor, "color") ADD_TYPE(CClientArea, "client area") ADD_TYPE(CGUIString, "text") + ADD_TYPE(EAlign, "align") + ADD_TYPE(EVAlign, "valign") else { throw PS_FAIL; @@ -329,7 +333,7 @@ void IGUIObject::UpdateCachedSize() if (absolute == false && m_pParent) m_CachedActualSize = ca.GetClientArea(m_pParent->m_CachedActualSize); else - m_CachedActualSize = ca.GetClientArea(CRect(0, 0, g_xres, g_yres)); + m_CachedActualSize = ca.GetClientArea(CRect(0.f, 0.f, (float)g_xres, (float)g_yres)); } diff --git a/source/gui/IGUIObject.h b/source/gui/IGUIObject.h index a4904921ba..53d146c003 100755 --- a/source/gui/IGUIObject.h +++ b/source/gui/IGUIObject.h @@ -60,11 +60,6 @@ typedef std::map map_Settings; // Declarations //-------------------------------------------------------- - -// Text alignments -enum EAlign { EAlign_Left, EAlign_Right, EAlign_Center }; -enum EValign { EValign_Top, EValign_Bottom, EValign_Center }; - /** * Setting Type * @see SGUISetting @@ -80,7 +75,9 @@ enum EGUISettingType GUIST_CColor, GUIST_CClientArea, GUIST_CGUIString, - GUIST_CStr + GUIST_CStr, + GUIST_EAlign, + GUIST_EVAlign }; /** diff --git a/source/gui/IGUITextOwner.cpp b/source/gui/IGUITextOwner.cpp index 6148805e87..9932a3a6b9 100755 --- a/source/gui/IGUITextOwner.cpp +++ b/source/gui/IGUITextOwner.cpp @@ -42,7 +42,8 @@ void IGUITextOwner::HandleMessage(const SGUIMessage &Message) // 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")) + Message.value == CStr("font") || Message.value == CStr("textcolor") || + Message.value == CStr("buffer-zone")) { SetupText(); }