Index: ps/trunk/source/gui/CTooltip.cpp =================================================================== --- ps/trunk/source/gui/CTooltip.cpp (revision 23027) +++ ps/trunk/source/gui/CTooltip.cpp (nonexistent) @@ -1,163 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CTooltip.h" - -#include "gui/CGUI.h" -#include "gui/CGUIString.h" -#include "gui/CGUIText.h" - -#include - -CTooltip::CTooltip(CGUI& pGUI) - : IGUIObject(pGUI), - IGUITextOwner(*static_cast(this)), - m_BufferZone(), - m_Caption(), - m_Font(), - m_Sprite(), - m_Delay(), - m_TextColor(), - m_MaxWidth(), - m_Offset(), - m_Anchor(), - m_TextAlign(), - m_Independent(), - m_MousePos(), - m_UseObject(), - m_HideObject() -{ - // If the tooltip is an object by itself: - RegisterSetting("buffer_zone", m_BufferZone); - RegisterSetting("caption", m_Caption); - RegisterSetting("font", m_Font); - RegisterSetting("sprite", m_Sprite); - RegisterSetting("delay", m_Delay); // in milliseconds - RegisterSetting("textcolor", m_TextColor); - RegisterSetting("maxwidth", m_MaxWidth); - RegisterSetting("offset", m_Offset); - RegisterSetting("anchor", m_Anchor); - RegisterSetting("text_align", m_TextAlign); - // This is used for tooltips that are hidden/revealed manually by scripts, rather than through the standard tooltip display mechanism - RegisterSetting("independent", m_Independent); - // Private settings: - // This is set by GUITooltip - RegisterSetting("_mousepos", m_MousePos); - // If the tooltip is just a reference to another object: - RegisterSetting("use_object", m_UseObject); - RegisterSetting("hide_object", m_HideObject); - - // Defaults - SetSetting("delay", 500, true); - SetSetting("anchor", EVAlign_Bottom, true); - SetSetting("text_align", EAlign_Left, true); - - // Set up a blank piece of text, to be replaced with a more - // interesting message later - AddText(); -} - -CTooltip::~CTooltip() -{ -} - -void CTooltip::SetupText() -{ - ENSURE(m_GeneratedTexts.size() == 1); - - m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_MaxWidth, m_BufferZone, this); - - // Position the tooltip relative to the mouse: - - const CPos& mousepos = m_Independent ? m_pGUI.GetMousePos() : m_MousePos; - - float textwidth = m_GeneratedTexts[0].GetSize().cx; - float textheight = m_GeneratedTexts[0].GetSize().cy; - - CGUISize size; - size.pixel.left = mousepos.x + m_Offset.x; - size.pixel.right = size.pixel.left + textwidth; - - switch (m_Anchor) - { - case EVAlign_Top: - size.pixel.top = mousepos.y + m_Offset.y; - size.pixel.bottom = size.pixel.top + textheight; - break; - case EVAlign_Bottom: - size.pixel.bottom = mousepos.y + m_Offset.y; - size.pixel.top = size.pixel.bottom - textheight; - break; - case EVAlign_Center: - size.pixel.top = mousepos.y + m_Offset.y - textheight/2.f; - size.pixel.bottom = size.pixel.top + textwidth; - break; - default: - debug_warn(L"Invalid EVAlign!"); - } - - - // Reposition the tooltip if it's falling off the screen: - - extern int g_xres, g_yres; - extern float g_GuiScale; - float screenw = g_xres / g_GuiScale; - float screenh = g_yres / g_GuiScale; - - if (size.pixel.top < 0.f) - size.pixel.bottom -= size.pixel.top, size.pixel.top = 0.f; - else if (size.pixel.bottom > screenh) - size.pixel.top -= (size.pixel.bottom-screenh), size.pixel.bottom = screenh; - - if (size.pixel.left < 0.f) - size.pixel.right -= size.pixel.left, size.pixel.left = 0.f; - else if (size.pixel.right > screenw) - size.pixel.left -= (size.pixel.right-screenw), size.pixel.right = screenw; - - SetSetting("size", size, true); -} - -void CTooltip::UpdateCachedSize() -{ - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); -} - -void CTooltip::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - IGUITextOwner::HandleMessage(Message); -} - -void CTooltip::Draw() -{ - float z = 900.f; // TODO: Find a nicer way of putting the tooltip on top of everything else - - // Normally IGUITextOwner will handle this updating but since SetupText can modify the position - // we need to call it now *before* we do the rest of the drawing - if (!m_GeneratedTextsValid) - { - SetupText(); - m_GeneratedTextsValid = true; - } - - m_pGUI.DrawSprite(m_Sprite, 0, z, m_CachedActualSize); - - DrawText(0, m_TextColor, m_CachedActualSize.TopLeft(), z + 0.1f); -} Property changes on: ps/trunk/source/gui/CTooltip.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CChart.h =================================================================== --- ps/trunk/source/gui/CChart.h (revision 23027) +++ ps/trunk/source/gui/CChart.h (nonexistent) @@ -1,111 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CCHART -#define INCLUDED_CCHART - -#include "graphics/ShaderProgramPtr.h" -#include "gui/CGUIColor.h" -#include "gui/CGUIList.h" -#include "gui/CGUISeries.h" -#include "gui/IGUITextOwner.h" -#include "maths/Vector2D.h" - -#include - -struct CChartData -{ - // Avoid copying the container. - NONCOPYABLE(CChartData); - MOVABLE(CChartData); - CChartData() = default; - - CGUIColor m_Color; - std::vector m_Points; -}; - -/** - * Chart for a data visualization as lines or points - */ -class CChart : public IGUIObject, public IGUITextOwner -{ - GUI_OBJECT(CChart) - -public: - CChart(CGUI& pGUI); - virtual ~CChart(); - -protected: - /** - * @see IGUIObject#UpdateCachedSize() - */ - void UpdateCachedSize(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * Draws the Chart - */ - virtual void Draw(); - - virtual CRect GetChartRect() const; - - void UpdateSeries(); - - void SetupText(); - - std::vector m_Series; - - CVector2D m_LeftBottom, m_RightTop; - - std::vector m_TextPositions; - - bool m_EqualX, m_EqualY; - - // Settings - CGUIColor m_AxisColor; - float m_AxisWidth; - float m_BufferZone; - CStrW m_Font; - CStrW m_FormatX; - CStrW m_FormatY; - CGUIList m_SeriesColor; - CGUISeries m_SeriesSetting; - EAlign m_TextAlign; - -private: - /** - * Helper functions - */ - void DrawLine(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const; - - // Draws the triangle sequence so that the each next triangle has a common edge with the previous one. - // If we need to draw n triangles, we need only n + 2 points. - void DrawTriangleStrip(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const; - - // Represents axes as triangles and draws them with DrawTriangleStrip. - void DrawAxes(const CShaderProgramPtr& shader) const; - - CSize AddFormattedValue(const CStrW& format, const float value, const CStrW& font, const float buffer_zone); - - void UpdateBounds(); -}; - -#endif // INCLUDED_CCHART Property changes on: ps/trunk/source/gui/CChart.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CInput.h =================================================================== --- ps/trunk/source/gui/CInput.h (revision 23027) +++ ps/trunk/source/gui/CInput.h (nonexistent) @@ -1,212 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CINPUT -#define INCLUDED_CINPUT - -#include "gui/IGUIScrollBarOwner.h" -#include "gui/CGUISprite.h" -#include "lib/external_libraries/libsdl.h" - -#include - -/** - * Text field where you can input and edit the text. - * - * It doesn't use IGUITextOwner, because we don't need - * any other features than word-wrapping, and we need to be - * able to rapidly change the string. - */ -class CInput : public IGUIObject, public IGUIScrollBarOwner -{ - GUI_OBJECT(CInput) - -protected: // forwards - struct SRow; - -public: - CInput(CGUI& pGUI); - virtual ~CInput(); - - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - // Check where the mouse is hovering, and get the appropriate text position. - // return is the text-position index. - int GetMouseHoveringTextPosition() const; - - // Same as above, but only on one row in X, and a given value, not the mouse's. - // wanted is filled with x if the row didn't extend as far as the mouse pos. - int GetXTextPosition(const std::list::const_iterator& c, const float& x, float& wanted) const; - -protected: - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * Handle events manually to catch keyboard inputting. - */ - virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev); - - /** - * Handle events manually to catch keys which change the text. - */ - virtual void ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode); - - /** - * Handle events manually to catch keys which don't change the text. - */ - virtual void ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode); - - /** - * Handle hotkey events (called by ManuallyHandleEvent) - */ - virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev); - - /** - * @see IGUIObject#UpdateCachedSize() - */ - virtual void UpdateCachedSize(); - - /** - * Draws the Text - */ - virtual void Draw(); - - /** - * Calculate m_CharacterPosition - * the main task for this function is to perfom word-wrapping - * You input from which character it has been changed, because - * if we add a character to the very last end, we don't want - * process everything all over again! Also notice you can - * specify a 'to' also, it will only be used though if a '\n' - * appears, because then the word-wrapping won't change after - * that. - */ - void UpdateText(int from = 0, int to_before = -1, int to_after = -1); - - /** - * Delete the current selection. Also places the pointer at the - * crack between the two segments kept. - */ - void DeleteCurSelection(); - - /** - * Is text selected? It can be denote two ways, m_iBufferPos_Tail - * being -1 or the same as m_iBufferPos. This makes for clearer - * code. - */ - bool SelectingText() const; - - /// Get area of where text can be drawn. - float GetTextAreaWidth(); - - /// Called every time the auto-scrolling should be checked. - void UpdateAutoScroll(); - - /// Clear composed IME input when supported (SDL2 only). - void ClearComposedText(); - - /// Updates the buffer (cursor) position exposed to JS. - void UpdateBufferPositionSetting(); -protected: - /// Cursor position - int m_iBufferPos; - /// Cursor position we started to select from. (-1 if not selecting) - /// (NB: Can be larger than m_iBufferPos if selecting from back to front.) - int m_iBufferPos_Tail; - - /// If we're composing text with an IME - bool m_ComposingText; - /// The length and position of the current IME composition - int m_iComposedLength, m_iComposedPos; - /// The position to insert committed text - int m_iInsertPos; - - // the outer vector is lines, and the inner is X positions - // in a row. So that we can determine where characters are - // placed. It's important because we need to know where the - // pointer should be placed when the input control is pressed. - struct SRow - { - // Where the Row starts - int m_ListStart; - - // List of X values for each character. - std::vector m_ListOfX; - }; - - /** - * List of rows to ease changing its size, so iterators stay valid. - * For one-liners only one row is used. - */ - std::list m_CharacterPositions; - - // *** Things for a multi-lined input control *** // - - /** - * When you change row with up/down, and the row you jump to does - * not have anything at that X position, then it will keep the - * m_WantedX position in mind when switching to the next row. - * It will keep on being used until it reach a row which meets the - * requirements. - * 0.0f means not in use. - */ - float m_WantedX; - - /** - * If we are in the process of selecting a larger selection of text - * using the mouse click (hold) and drag, this is true. - */ - bool m_SelectingText; - - // *** Things for one-line input control *** // - float m_HorizontalScroll; - - /// Used to store the previous time for flashing the cursor. - double m_PrevTime; - - /// Cursor blink rate in seconds, if greater than 0.0. - double m_CursorBlinkRate; - - /// If the cursor should be drawn or not. - bool m_CursorVisState; - - // Settings - i32 m_BufferPosition; - float m_BufferZone; - CStrW m_Caption; - i32 m_CellID; - CStrW m_Font; - CStrW m_MaskChar; - bool m_Mask; - i32 m_MaxLength; - bool m_MultiLine; - bool m_Readonly; - bool m_ScrollBar; - CStr m_ScrollBarStyle; - CGUISpriteInstance m_Sprite; - CGUISpriteInstance m_SpriteSelectArea; - CGUIColor m_TextColor; - CGUIColor m_TextColorSelected; -}; - -#endif // INCLUDED_CINPUT Property changes on: ps/trunk/source/gui/CInput.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CDropDown.h =================================================================== --- ps/trunk/source/gui/CDropDown.h (revision 23027) +++ ps/trunk/source/gui/CDropDown.h (nonexistent) @@ -1,142 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* -GUI Object - Drop Down (list) - ---Overview-- - - Works just like a list-box, but it hides - all the elements that aren't selected. They - can be brought up by pressing the control. -*/ - -#ifndef INCLUDED_CDROPDOWN -#define INCLUDED_CDROPDOWN - -#include "gui/CGUISprite.h" -#include "gui/CList.h" - -#include - -/** - * Drop Down - * - * The control can be pressed, but we will not inherent - * this behavior from IGUIButtonBehavior, because when - * you press this control, the list with elements will - * immediately appear, and not first after release - * (which is the whole gist of the IGUIButtonBehavior). - */ -class CDropDown : public CList -{ - GUI_OBJECT(CDropDown) - -public: - CDropDown(CGUI& pGUI); - virtual ~CDropDown(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * Handle events manually to catch keyboard inputting. - */ - virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev); - - /** - * Draws the Button - */ - virtual void Draw(); - - // This is one of the few classes we actually need to redefine this function - // this is because the size of the control changes whether it is open - // or closed. - virtual bool IsMouseOver() const; - - virtual float GetBufferedZ() const; - -protected: - /** - * If the size changed, the texts have to be updated as - * the word wrapping depends on the size. - */ - virtual void UpdateCachedSize(); - - /** - * Sets up text, should be called every time changes has been - * made that can change the visual. - */ - void SetupText(); - - // Sets up the cached GetListRect. Decided whether it should - // have a scrollbar, and so on. - virtual void SetupListRect(); - - // Specify a new List rectangle. - virtual CRect GetListRect() const; - - /** - * Placement of text. - */ - CPos m_TextPos; - - // Is the dropdown opened? - bool m_Open; - - // I didn't cache this at first, but it's just as easy as caching - // m_CachedActualSize, so I thought, what the heck it's used a lot. - CRect m_CachedListRect; - - // Hide scrollbar when it's not needed - bool m_HideScrollBar; - - // Not necessarily the element that is selected, this is just - // which element should be highlighted. When opening the dropdown - // it is set to "selected", but then when moving the mouse it will - // change. - int m_ElementHighlight; - - // Stores any text entered by the user for quick access to an element - // (ie if you type "acro" it will take you to acropolis). - std::string m_InputBuffer; - - // used to know if we want to restart anew or add to m_inputbuffer. - double m_TimeOfLastInput; - - // Settings - float m_ButtonWidth; - float m_DropDownSize; - float m_DropDownBuffer; - u32 m_MinimumVisibleItems; - CStrW m_SoundClosed; - CStrW m_SoundEnter; - CStrW m_SoundLeave; - CStrW m_SoundOpened; - CGUISpriteInstance m_SpriteDisabled; - CGUISpriteInstance m_SpriteList; - CGUISpriteInstance m_Sprite2; - CGUISpriteInstance m_Sprite2Over; - CGUISpriteInstance m_Sprite2Pressed; - CGUISpriteInstance m_Sprite2Disabled; - CGUIColor m_TextColorDisabled; - EVAlign m_TextVAlign; -}; - -#endif // INCLUDED_CDROPDOWN Property changes on: ps/trunk/source/gui/CDropDown.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUIButtonBehavior.cpp =================================================================== --- ps/trunk/source/gui/IGUIButtonBehavior.cpp (revision 23027) +++ ps/trunk/source/gui/IGUIButtonBehavior.cpp (nonexistent) @@ -1,148 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "IGUIButtonBehavior.h" - -#include "gui/CGUISprite.h" - -IGUIButtonBehavior::IGUIButtonBehavior(IGUIObject& pObject) - : m_pObject(pObject), - m_Pressed(), - m_PressedRight(), - m_SoundDisabled(), - m_SoundEnter(), - m_SoundLeave(), - m_SoundPressed(), - m_SoundReleased() -{ - m_pObject.RegisterSetting("sound_disabled", m_SoundDisabled); - m_pObject.RegisterSetting("sound_enter", m_SoundEnter); - m_pObject.RegisterSetting("sound_leave", m_SoundLeave); - m_pObject.RegisterSetting("sound_pressed", m_SoundPressed); - m_pObject.RegisterSetting("sound_released", m_SoundReleased); -} - -IGUIButtonBehavior::~IGUIButtonBehavior() -{ -} - -void IGUIButtonBehavior::ResetStates() -{ - m_Pressed = false; - m_PressedRight = false; -} - -void IGUIButtonBehavior::HandleMessage(SGUIMessage& Message) -{ - // TODO Gee: easier access functions - switch (Message.type) - { - case GUIM_MOUSE_ENTER: - if (m_pObject.IsEnabled()) - m_pObject.PlaySound(m_SoundEnter); - break; - - case GUIM_MOUSE_LEAVE: - if (m_pObject.IsEnabled()) - m_pObject.PlaySound(m_SoundLeave); - break; - - case GUIM_MOUSE_DBLCLICK_LEFT: - if (!m_pObject.IsEnabled()) - break; - - // Since GUIM_MOUSE_PRESS_LEFT also gets called twice in a - // doubleclick event, we let it handle playing sounds. - m_pObject.SendEvent(GUIM_DOUBLE_PRESSED, "doublepress"); - break; - - case GUIM_MOUSE_PRESS_LEFT: - if (!m_pObject.IsEnabled()) - { - m_pObject.PlaySound(m_SoundDisabled); - break; - } - - m_pObject.PlaySound(m_SoundPressed); - m_pObject.SendEvent(GUIM_PRESSED, "press"); - m_Pressed = true; - break; - - case GUIM_MOUSE_DBLCLICK_RIGHT: - if (!m_pObject.IsEnabled()) - break; - - // Since GUIM_MOUSE_PRESS_RIGHT also gets called twice in a - // doubleclick event, we let it handle playing sounds. - m_pObject.SendEvent(GUIM_DOUBLE_PRESSED_MOUSE_RIGHT, "doublepressright"); - break; - - case GUIM_MOUSE_PRESS_RIGHT: - if (!m_pObject.IsEnabled()) - { - m_pObject.PlaySound(m_SoundDisabled); - break; - } - - // Button was right-clicked - m_pObject.PlaySound(m_SoundPressed); - m_pObject.SendEvent(GUIM_PRESSED_MOUSE_RIGHT, "pressright"); - m_PressedRight = true; - break; - - case GUIM_MOUSE_RELEASE_RIGHT: - if (!m_pObject.IsEnabled()) - break; - - if (m_PressedRight) - { - m_PressedRight = false; - m_pObject.PlaySound(m_SoundReleased); - } - break; - - case GUIM_MOUSE_RELEASE_LEFT: - if (!m_pObject.IsEnabled()) - break; - - if (m_Pressed) - { - m_Pressed = false; - m_pObject.PlaySound(m_SoundReleased); - } - break; - - default: - break; - } -} - -const CGUISpriteInstance& IGUIButtonBehavior::GetButtonSprite(const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_over, const CGUISpriteInstance& sprite_pressed, const CGUISpriteInstance& sprite_disabled) const -{ - if (!m_pObject.IsEnabled()) - return sprite_disabled || sprite; - - if (!m_pObject.IsMouseOver()) - return sprite; - - if (m_Pressed) - return sprite_pressed || sprite; - - return sprite_over || sprite; -} Property changes on: ps/trunk/source/gui/IGUIButtonBehavior.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CList.cpp =================================================================== --- ps/trunk/source/gui/CList.cpp (revision 23027) +++ ps/trunk/source/gui/CList.cpp (nonexistent) @@ -1,483 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CList.h" - -#include "gui/CGUI.h" -#include "gui/CGUIColor.h" -#include "gui/CGUIList.h" -#include "gui/CGUIScrollBarVertical.h" -#include "lib/external_libraries/libsdl.h" -#include "lib/timer.h" - -CList::CList(CGUI& pGUI) - : IGUIObject(pGUI), - IGUITextOwner(*static_cast(this)), - IGUIScrollBarOwner(*static_cast(this)), - m_Modified(false), - m_PrevSelectedItem(-1), - m_LastItemClickTime(0), - m_BufferZone(), - m_Font(), - m_ScrollBar(), - m_ScrollBarStyle(), - m_SoundDisabled(), - m_SoundSelected(), - m_Sprite(), - m_SpriteSelectArea(), - m_CellID(), - m_TextAlign(), - m_TextColor(), - m_TextColorSelected(), - m_Selected(), - m_AutoScroll(), - m_Hovered(), - m_List(), - m_ListData() -{ - RegisterSetting("buffer_zone", m_BufferZone); - RegisterSetting("font", m_Font); - RegisterSetting("scrollbar", m_ScrollBar); - RegisterSetting("scrollbar_style", m_ScrollBarStyle); - RegisterSetting("sound_disabled", m_SoundDisabled); - RegisterSetting("sound_selected", m_SoundSelected); - RegisterSetting("sprite", m_Sprite); - // Add sprite_disabled! TODO - RegisterSetting("sprite_selectarea", m_SpriteSelectArea); - RegisterSetting("cell_id", m_CellID); - RegisterSetting("text_align", m_TextAlign); - RegisterSetting("textcolor", m_TextColor); - RegisterSetting("textcolor_selected", m_TextColorSelected); - RegisterSetting("selected", m_Selected); // Index selected. -1 is none. - RegisterSetting("auto_scroll", m_AutoScroll); - RegisterSetting("hovered", m_Hovered); - // Each list item has both a name (in 'list') and an associated data string (in 'list_data') - RegisterSetting("list", m_List); - RegisterSetting("list_data", m_ListData); - - SetSetting("scrollbar", false, true); - SetSetting("selected", -1, true); - SetSetting("hovered", -1, true); - SetSetting("auto_scroll", false, true); - - // Add scroll-bar - CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI); - bar->SetRightAligned(true); - AddScrollBar(bar); -} - -CList::~CList() -{ -} - -void CList::SetupText() -{ - m_Modified = true; - - m_ItemsYPositions.resize(m_List.m_Items.size() + 1); - - // Delete all generated texts. Some could probably be saved, - // but this is easier, and this function will never be called - // continuously, or even often, so it'll probably be okay. - m_GeneratedTexts.clear(); - - float width = GetListRect().GetWidth(); - // remove scrollbar if applicable - if (m_ScrollBar && GetScrollBar(0).GetStyle()) - width -= GetScrollBar(0).GetStyle()->m_Width; - - // Generate texts - float buffered_y = 0.f; - - for (size_t i = 0; i < m_List.m_Items.size(); ++i) - { - CGUIText* text; - - if (!m_List.m_Items[i].GetOriginalString().empty()) - text = &AddText(m_List.m_Items[i], m_Font, width, m_BufferZone); - else - { - // Minimum height of a space character of the current font size - CGUIString align_string; - align_string.SetValue(L" "); - text = &AddText(align_string, m_Font, width, m_BufferZone); - } - - m_ItemsYPositions[i] = buffered_y; - buffered_y += text->GetSize().cy; - } - - m_ItemsYPositions[m_List.m_Items.size()] = buffered_y; - - // Setup scrollbar - if (m_ScrollBar) - { - GetScrollBar(0).SetScrollRange(m_ItemsYPositions.back()); - GetScrollBar(0).SetScrollSpace(GetListRect().GetHeight()); - - CRect rect = GetListRect(); - GetScrollBar(0).SetX(rect.right); - GetScrollBar(0).SetY(rect.top); - GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(rect.bottom - rect.top); - } -} - -void CList::ResetStates() -{ - IGUIObject::ResetStates(); - IGUIScrollBarOwner::ResetStates(); -} - -void CList::UpdateCachedSize() -{ - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); -} - -void CList::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - IGUIScrollBarOwner::HandleMessage(Message); - //IGUITextOwner::HandleMessage(Message); <== placed it after the switch instead! - - m_Modified = false; - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - if (Message.value == "list") - SetupText(); - - // If selected is changed, call "SelectionChange" - if (Message.value == "selected") - { - // TODO: Check range - - if (m_AutoScroll) - UpdateAutoScroll(); - - // TODO only works if lower-case, shouldn't it be made case sensitive instead? - ScriptEvent("selectionchange"); - } - - if (Message.value == "scrollbar") - SetupText(); - - // Update scrollbar - if (Message.value == "scrollbar_style") - { - GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); - SetupText(); - } - - break; - - case GUIM_MOUSE_PRESS_LEFT: - { - if (!m_Enabled) - { - PlaySound(m_SoundDisabled); - break; - } - - int hovered = GetHoveredItem(); - if (hovered == -1) - break; - SetSetting("selected", hovered, true); - UpdateAutoScroll(); - PlaySound(m_SoundSelected); - - if (timer_Time() - m_LastItemClickTime < SELECT_DBLCLICK_RATE && hovered == m_PrevSelectedItem) - this->SendEvent(GUIM_MOUSE_DBLCLICK_LEFT_ITEM, "mouseleftdoubleclickitem"); - else - this->SendEvent(GUIM_MOUSE_PRESS_LEFT_ITEM, "mouseleftclickitem"); - - m_LastItemClickTime = timer_Time(); - m_PrevSelectedItem = hovered; - break; - } - - case GUIM_MOUSE_LEAVE: - { - if (m_Hovered == -1) - break; - - SetSetting("hovered", -1, true); - ScriptEvent("hoverchange"); - break; - } - - case GUIM_MOUSE_OVER: - { - int hovered = GetHoveredItem(); - if (hovered == m_Hovered) - break; - - SetSetting("hovered", hovered, true); - ScriptEvent("hoverchange"); - break; - } - - case GUIM_LOAD: - { - GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); - break; - } - - default: - break; - } - - IGUITextOwner::HandleMessage(Message); -} - -InReaction CList::ManuallyHandleEvent(const SDL_Event_* ev) -{ - InReaction result = IN_PASS; - - if (ev->ev.type == SDL_KEYDOWN) - { - int szChar = ev->ev.key.keysym.sym; - - switch (szChar) - { - case SDLK_HOME: - SelectFirstElement(); - UpdateAutoScroll(); - result = IN_HANDLED; - break; - - case SDLK_END: - SelectLastElement(); - UpdateAutoScroll(); - result = IN_HANDLED; - break; - - case SDLK_UP: - SelectPrevElement(); - UpdateAutoScroll(); - result = IN_HANDLED; - break; - - case SDLK_DOWN: - SelectNextElement(); - UpdateAutoScroll(); - result = IN_HANDLED; - break; - - case SDLK_PAGEUP: - GetScrollBar(0).ScrollMinusPlenty(); - result = IN_HANDLED; - break; - - case SDLK_PAGEDOWN: - GetScrollBar(0).ScrollPlusPlenty(); - result = IN_HANDLED; - break; - - default: // Do nothing - result = IN_PASS; - } - } - - return result; -} - -void CList::Draw() -{ - DrawList(m_Selected, m_Sprite, m_SpriteSelectArea, m_TextColor); -} - -void CList::DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selectarea, const CGUIColor& textcolor) -{ - float bz = GetBufferedZ(); - - // First call draw on ScrollBarOwner - if (m_ScrollBar) - IGUIScrollBarOwner::Draw(); - - { - CRect rect = GetListRect(); - - m_pGUI.DrawSprite(sprite, m_CellID, bz, rect); - - float scroll = 0.f; - if (m_ScrollBar) - scroll = GetScrollBar(0).GetPos(); - - if (selected >= 0 && selected+1 < (int)m_ItemsYPositions.size()) - { - // Get rectangle of selection: - CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, - rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll); - - if (rect_sel.top <= rect.bottom && - rect_sel.bottom >= rect.top) - { - if (rect_sel.bottom > rect.bottom) - rect_sel.bottom = rect.bottom; - if (rect_sel.top < rect.top) - rect_sel.top = rect.top; - - if (m_ScrollBar) - { - // Remove any overlapping area of the scrollbar. - if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && - rect_sel.right <= GetScrollBar(0).GetOuterRect().right) - rect_sel.right = GetScrollBar(0).GetOuterRect().left; - - if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && - rect_sel.left < GetScrollBar(0).GetOuterRect().right) - rect_sel.left = GetScrollBar(0).GetOuterRect().right; - } - - m_pGUI.DrawSprite(sprite_selectarea, m_CellID, bz + 0.05f, rect_sel); - } - } - - for (size_t i = 0; i < m_List.m_Items.size(); ++i) - { - if (m_ItemsYPositions[i+1] - scroll < 0 || - m_ItemsYPositions[i] - scroll > rect.GetHeight()) - continue; - - // Clipping area (we'll have to substract the scrollbar) - CRect cliparea = GetListRect(); - - if (m_ScrollBar) - { - if (cliparea.right > GetScrollBar(0).GetOuterRect().left && - cliparea.right <= GetScrollBar(0).GetOuterRect().right) - cliparea.right = GetScrollBar(0).GetOuterRect().left; - - if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && - cliparea.left < GetScrollBar(0).GetOuterRect().right) - cliparea.left = GetScrollBar(0).GetOuterRect().right; - } - - DrawText(i, textcolor, rect.TopLeft() - CPos(0.f, scroll - m_ItemsYPositions[i]), bz + 0.1f, cliparea); - } - } -} - -void CList::AddItem(const CStrW& str, const CStrW& data) -{ - CGUIString gui_string; - gui_string.SetValue(str); - - // Do not send a settings-changed message - m_List.m_Items.push_back(gui_string); - - CGUIString data_string; - data_string.SetValue(data); - - m_ListData.m_Items.push_back(data_string); - - // TODO Temp - SetupText(); -} - -bool CList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile) -{ - int elmt_item = pFile->GetElementID("item"); - - if (child.GetNodeName() == elmt_item) - { - AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8()); - return true; - } - - return false; -} - -void CList::SelectNextElement() -{ - if (m_Selected != static_cast(m_List.m_Items.size()) - 1) - { - SetSetting("selected", m_Selected + 1, true); - PlaySound(m_SoundSelected); - } -} - -void CList::SelectPrevElement() -{ - if (m_Selected > 0) - { - SetSetting("selected", m_Selected - 1, true); - PlaySound(m_SoundSelected); - } -} - -void CList::SelectFirstElement() -{ - if (m_Selected >= 0) - SetSetting("selected", 0, true); -} - -void CList::SelectLastElement() -{ - const int index = static_cast(m_List.m_Items.size()) - 1; - - if (m_Selected != index) - SetSetting("selected", index, true); -} - -void CList::UpdateAutoScroll() -{ - // No scrollbar, no scrolling (at least it's not made to work properly). - if (!m_ScrollBar || m_Selected < 0 || static_cast(m_Selected) >= m_ItemsYPositions.size()) - return; - - float scroll = GetScrollBar(0).GetPos(); - - // Check upper boundary - if (m_ItemsYPositions[m_Selected] < scroll) - { - GetScrollBar(0).SetPos(m_ItemsYPositions[m_Selected]); - return; // this means, if it wants to align both up and down at the same time - // this will have precedence. - } - - // Check lower boundary - CRect rect = GetListRect(); - if (m_ItemsYPositions[m_Selected+1]-rect.GetHeight() > scroll) - GetScrollBar(0).SetPos(m_ItemsYPositions[m_Selected+1]-rect.GetHeight()); -} - -int CList::GetHoveredItem() -{ - const float scroll = m_ScrollBar ? GetScrollBar(0).GetPos() : 0.f; - - const CRect& rect = GetListRect(); - CPos mouse = m_pGUI.GetMousePos(); - mouse.y += scroll; - - // Mouse is over scrollbar - if (m_ScrollBar && GetScrollBar(0).IsVisible() && - mouse.x >= GetScrollBar(0).GetOuterRect().left && - mouse.x <= GetScrollBar(0).GetOuterRect().right) - return -1; - - for (size_t i = 0; i < m_List.m_Items.size(); ++i) - if (mouse.y >= rect.top + m_ItemsYPositions[i] && - mouse.y < rect.top + m_ItemsYPositions[i + 1]) - return i; - - return -1; -} Property changes on: ps/trunk/source/gui/CList.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CRadioButton.cpp =================================================================== --- ps/trunk/source/gui/CRadioButton.cpp (revision 23027) +++ ps/trunk/source/gui/CRadioButton.cpp (nonexistent) @@ -1,48 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CRadioButton.h" - -CRadioButton::CRadioButton(CGUI& pGUI) - : CCheckBox(pGUI) -{ -} - -void CRadioButton::HandleMessage(SGUIMessage& Message) -{ - IGUIButtonBehavior::HandleMessage(Message); - - switch (Message.type) - { - case GUIM_PRESSED: - for (IGUIObject* const& obj : GetParent()->GetChildren()) - { - // Notice, if you use other objects within the parent object that has got - // the setting "checked", it too will change. Hence NO OTHER OBJECTS THAN - // RADIO BUTTONS SHOULD BE WITHIN IT! - obj->SetSetting("checked", false, true); - } - - SetSetting("checked", true, true); - break; - - default: - break; - } -} Property changes on: ps/trunk/source/gui/CRadioButton.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CProgressBar.h =================================================================== --- ps/trunk/source/gui/CProgressBar.h (revision 23027) +++ ps/trunk/source/gui/CProgressBar.h (nonexistent) @@ -1,53 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CPROGRESSBAR -#define INCLUDED_CPROGRESSBAR - -#include "gui/IGUIObject.h" -#include "gui/CGUISprite.h" - -/** - * Object used to draw a value (e.g. progress) from 0 to 100 visually. - */ -class CProgressBar : public IGUIObject -{ - GUI_OBJECT(CProgressBar) - -public: - CProgressBar(CGUI& pGUI); - virtual ~CProgressBar(); - -protected: - /** - * Draws the progress bar - */ - virtual void Draw(); - - // If caption is set, make sure it's within the interval 0-100 - /** - * @see IGUIObject#HandleMessage() - */ - void HandleMessage(SGUIMessage& Message); - - // Settings - CGUISpriteInstance m_SpriteBackground; - CGUISpriteInstance m_SpriteBar; - float m_Caption; -}; - -#endif // INCLUDED_CPROGRESSBAR Property changes on: ps/trunk/source/gui/CProgressBar.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CButton.h =================================================================== --- ps/trunk/source/gui/CButton.h (revision 23027) +++ ps/trunk/source/gui/CButton.h (nonexistent) @@ -1,89 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CBUTTON -#define INCLUDED_CBUTTON - -#include "gui/IGUIButtonBehavior.h" -#include "gui/IGUIObject.h" -#include "gui/IGUITextOwner.h" -#include "gui/CGUISprite.h" -#include "gui/CGUIString.h" - -class CButton : public IGUIObject, public IGUITextOwner, public IGUIButtonBehavior -{ - GUI_OBJECT(CButton) - -public: - CButton(CGUI& pGUI); - virtual ~CButton(); - - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - /** - * @see IGUIObject#UpdateCachedSize() - */ - virtual void UpdateCachedSize(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * 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(); - - /** - * Picks the text color depending on current object settings. - */ - const CGUIColor& ChooseColor(); - - /** - * Placement of text. - */ - CPos m_TextPos; - - // Settings - float m_BufferZone; - i32 m_CellID; - CGUIString m_Caption; - CStrW m_Font; - CGUISpriteInstance m_Sprite; - CGUISpriteInstance m_SpriteOver; - CGUISpriteInstance m_SpritePressed; - CGUISpriteInstance m_SpriteDisabled; - EAlign m_TextAlign; - EVAlign m_TextVAlign; - CGUIColor m_TextColor; - CGUIColor m_TextColorOver; - CGUIColor m_TextColorPressed; - CGUIColor m_TextColorDisabled; -}; - -#endif // INCLUDED_CBUTTON Property changes on: ps/trunk/source/gui/CButton.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/IGUIObject.cpp (revision 23027) +++ ps/trunk/source/gui/IGUIObject.cpp (nonexistent) @@ -1,550 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "IGUIObject.h" - -#include "gui/CGUI.h" -#include "gui/CGUISetting.h" -#include "ps/CLogger.h" -#include "ps/GameSetup/Config.h" -#include "ps/Profile.h" -#include "scriptinterface/ScriptInterface.h" -#include "soundmanager/ISoundManager.h" - -IGUIObject::IGUIObject(CGUI& pGUI) - : m_pGUI(pGUI), - m_pParent(), - m_MouseHovering(), - m_LastClickTime(), - m_Enabled(), - m_Hidden(), - m_Size(), - m_Style(), - m_Hotkey(), - m_Z(), - m_Absolute(), - m_Ghost(), - m_AspectRatio(), - m_Tooltip(), - m_TooltipStyle() -{ - RegisterSetting("enabled", m_Enabled); - RegisterSetting("hidden", m_Hidden); - RegisterSetting("size", m_Size); - RegisterSetting("style", m_Style); - RegisterSetting("hotkey", m_Hotkey); - RegisterSetting("z", m_Z); - RegisterSetting("absolute", m_Absolute); - RegisterSetting("ghost", m_Ghost); - RegisterSetting("aspectratio", m_AspectRatio); - RegisterSetting("tooltip", m_Tooltip); - RegisterSetting("tooltip_style", m_TooltipStyle); - - // Setup important defaults - // TODO: Should be in the default style? - SetSetting("hidden", false, true); - SetSetting("ghost", false, true); - SetSetting("enabled", true, true); - SetSetting("absolute", true, true); -} - -IGUIObject::~IGUIObject() -{ - for (const std::pair& p : m_Settings) - delete p.second; - - if (!m_ScriptHandlers.empty()) - JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this); -} - -//------------------------------------------------------------------- -// Functions -//------------------------------------------------------------------- - -void IGUIObject::AddChild(IGUIObject* pChild) -{ -// ENSURE(pChild); - - pChild->SetParent(this); - - m_Children.push_back(pChild); - - { - try - { - // Atomic function, if it fails it won't - // have changed anything - //UpdateObjects(); - pChild->GetGUI().UpdateObjects(); - } - catch (PSERROR_GUI&) - { - // If anything went wrong, reverse what we did and throw - // an exception telling it never added a child - m_Children.erase(m_Children.end()-1); - - throw; - } - } - // else do nothing -} - -void IGUIObject::AddToPointersMap(map_pObjects& ObjectMap) -{ - // Just don't do anything about the top node - if (m_pParent == nullptr) - return; - - // Now actually add this one - // notice we won't add it if it's doesn't have any parent - // (i.e. being the base object) - if (m_Name.empty()) - { - throw PSERROR_GUI_ObjectNeedsName(); - } - - if (ObjectMap.find(m_Name) != ObjectMap.end()) - { - throw PSERROR_GUI_NameAmbiguity(m_Name.c_str()); - } - else - { - ObjectMap[m_Name] = this; - } -} - -template -void IGUIObject::RegisterSetting(const CStr& Name, T& Value) -{ - if (SettingExists(Name)) - LOGERROR("The setting '%s' already exists on the object '%s'!", Name.c_str(), GetPresentableName().c_str()); - else - m_Settings.emplace(Name, new CGUISetting(*this, Name, Value)); -} - -bool IGUIObject::SettingExists(const CStr& Setting) const -{ - return m_Settings.find(Setting) != m_Settings.end(); -} - -template -T& IGUIObject::GetSetting(const CStr& Setting) -{ - return static_cast* >(m_Settings.at(Setting))->m_pSetting; -} - -template -const T& IGUIObject::GetSetting(const CStr& Setting) const -{ - return static_cast* >(m_Settings.at(Setting))->m_pSetting; -} - -bool IGUIObject::SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage) -{ - const std::map::iterator it = m_Settings.find(Setting); - if (it == m_Settings.end()) - { - LOGERROR("GUI object '%s' has no property called '%s', can't set parse and set value '%s'", GetPresentableName().c_str(), Setting.c_str(), Value.ToUTF8().c_str()); - return false; - } - return it->second->FromString(Value, SendMessage); -} - -template -void IGUIObject::SetSetting(const CStr& Setting, T& Value, const bool SendMessage) -{ - PreSettingChange(Setting); - static_cast* >(m_Settings.at(Setting))->m_pSetting = std::move(Value); - SettingChanged(Setting, SendMessage); -} - -template -void IGUIObject::SetSetting(const CStr& Setting, const T& Value, const bool SendMessage) -{ - PreSettingChange(Setting); - static_cast* >(m_Settings.at(Setting))->m_pSetting = Value; - SettingChanged(Setting, SendMessage); -} - -void IGUIObject::PreSettingChange(const CStr& Setting) -{ - if (Setting == "hotkey") - m_pGUI.UnsetObjectHotkey(this, GetSetting(Setting)); -} - -void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage) -{ - if (Setting == "size") - { - // If setting was "size", we need to re-cache itself and all children - RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); - } - else if (Setting == "hidden") - { - // Hiding an object requires us to reset it and all children - if (m_Hidden) - RecurseObject(nullptr, &IGUIObject::ResetStates); - } - else if (Setting == "hotkey") - m_pGUI.SetObjectHotkey(this, GetSetting(Setting)); - - if (SendMessage) - { - SGUIMessage msg(GUIM_SETTINGS_UPDATED, Setting); - HandleMessage(msg); - } -} - -bool IGUIObject::IsMouseOver() const -{ - return m_CachedActualSize.PointInside(m_pGUI.GetMousePos()); -} - -bool IGUIObject::MouseOverIcon() -{ - return false; -} - -void IGUIObject::UpdateMouseOver(IGUIObject* const& pMouseOver) -{ - if (pMouseOver == this) - { - if (!m_MouseHovering) - SendEvent(GUIM_MOUSE_ENTER, "mouseenter"); - - m_MouseHovering = true; - - SendEvent(GUIM_MOUSE_OVER, "mousemove"); - } - else - { - if (m_MouseHovering) - { - m_MouseHovering = false; - SendEvent(GUIM_MOUSE_LEAVE, "mouseleave"); - } - } -} - -void IGUIObject::ChooseMouseOverAndClosest(IGUIObject*& pObject) -{ - if (!IsMouseOver()) - return; - - // Check if we've got competition at all - if (pObject == nullptr) - { - pObject = this; - return; - } - - // Or if it's closer - if (GetBufferedZ() >= pObject->GetBufferedZ()) - { - pObject = this; - return; - } -} - -IGUIObject* IGUIObject::GetParent() const -{ - // Important, we're not using GetParent() for these - // checks, that could screw it up - if (m_pParent && m_pParent->m_pParent == nullptr) - return nullptr; - - return m_pParent; -} - -void IGUIObject::ResetStates() -{ - // Notify the gui that we aren't hovered anymore - UpdateMouseOver(nullptr); -} - -void IGUIObject::UpdateCachedSize() -{ - // 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_Absolute && m_pParent && !IsRootObject()) - m_CachedActualSize = m_Size.GetSize(m_pParent->m_CachedActualSize); - else - m_CachedActualSize = m_Size.GetSize(CRect(0.f, 0.f, g_xres / g_GuiScale, g_yres / g_GuiScale)); - - // In a few cases, GUI objects have to resize to fill the screen - // but maintain a constant aspect ratio. - // Adjust the size to be the max possible, centered in the original size: - if (m_AspectRatio) - { - if (m_CachedActualSize.GetWidth() > m_CachedActualSize.GetHeight() * m_AspectRatio) - { - float delta = m_CachedActualSize.GetWidth() - m_CachedActualSize.GetHeight() * m_AspectRatio; - m_CachedActualSize.left += delta/2.f; - m_CachedActualSize.right -= delta/2.f; - } - else - { - float delta = m_CachedActualSize.GetHeight() - m_CachedActualSize.GetWidth() / m_AspectRatio; - m_CachedActualSize.bottom -= delta/2.f; - m_CachedActualSize.top += delta/2.f; - } - } -} - -void IGUIObject::LoadStyle(const CStr& StyleName) -{ - if (!m_pGUI.HasStyle(StyleName)) - debug_warn(L"IGUIObject::LoadStyle failed"); - - // The default style may specify settings for any GUI object. - // Other styles are reported if they specify a Setting that does not exist, - // so that the XML author is informed and can correct the style. - - for (const std::pair& p : m_pGUI.GetStyle(StyleName).m_SettingsDefaults) - { - if (SettingExists(p.first)) - SetSettingFromString(p.first, p.second, true); - else if (StyleName != "default") - LOGWARNING("GUI object has no setting \"%s\", but the style \"%s\" defines it", p.first, StyleName.c_str()); - } -} - -float IGUIObject::GetBufferedZ() const -{ - if (m_Absolute) - return m_Z; - - if (GetParent()) - return GetParent()->GetBufferedZ() + m_Z; - - // In philosophy, a parentless object shouldn't be able to have a relative sizing, - // but we'll accept it so that absolute can be used as default without a complaint. - // Also, you could consider those objects children to the screen resolution. - return m_Z; -} - -void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI& pGUI) -{ - JSContext* cx = pGUI.GetScriptInterface()->GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue globalVal(cx, pGUI.GetGlobalObject()); - JS::RootedObject globalObj(cx, &globalVal.toObject()); - - const int paramCount = 1; - const char* paramNames[paramCount] = { "mouse" }; - - // Location to report errors from - CStr CodeName = GetName()+" "+Action; - - // Generate a unique name - static int x = 0; - char buf[64]; - sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d (%s)", x++, Action.c_str()); - - JS::CompileOptions options(cx); - options.setFileAndLine(CodeName.c_str(), 0); - options.setIsRunOnce(false); - - JS::RootedFunction func(cx); - JS::AutoObjectVector emptyScopeChain(cx); - if (!JS::CompileFunction(cx, emptyScopeChain, options, buf, paramCount, paramNames, Code.c_str(), Code.length(), &func)) - { - LOGERROR("RegisterScriptHandler: Failed to compile the script for %s", Action.c_str()); - return; - } - - JS::RootedObject funcObj(cx, JS_GetFunctionObject(func)); - SetScriptHandler(Action, funcObj); -} - -void IGUIObject::SetScriptHandler(const CStr& Action, JS::HandleObject Function) -{ - if (m_ScriptHandlers.empty()) - JS_AddExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this); - - m_ScriptHandlers[Action] = JS::Heap(Function); -} - -InReaction IGUIObject::SendEvent(EGUIMessageType type, const CStr& EventName) -{ - PROFILE2_EVENT("gui event"); - PROFILE2_ATTR("type: %s", EventName.c_str()); - PROFILE2_ATTR("object: %s", m_Name.c_str()); - - SGUIMessage msg(type); - HandleMessage(msg); - - ScriptEvent(EventName); - - return (msg.skipped ? IN_PASS : IN_HANDLED); -} - -void IGUIObject::ScriptEvent(const CStr& Action) -{ - std::map >::iterator it = m_ScriptHandlers.find(Action); - if (it == m_ScriptHandlers.end()) - return; - - JSContext* cx = m_pGUI.GetScriptInterface()->GetContext(); - JSAutoRequest rq(cx); - - // Set up the 'mouse' parameter - JS::RootedValue mouse(cx); - - const CPos& mousePos = m_pGUI.GetMousePos(); - - ScriptInterface::CreateObject( - cx, - &mouse, - "x", mousePos.x, - "y", mousePos.y, - "buttons", m_pGUI.GetMouseButtons()); - - JS::AutoValueVector paramData(cx); - paramData.append(mouse); - JS::RootedObject obj(cx, GetJSObject()); - JS::RootedValue handlerVal(cx, JS::ObjectValue(*it->second)); - JS::RootedValue result(cx); - bool ok = JS_CallFunctionValue(cx, obj, handlerVal, paramData, &result); - if (!ok) - { - // We have no way to propagate the script exception, so just ignore it - // and hope the caller checks JS_IsExceptionPending - } -} - -void IGUIObject::ScriptEvent(const CStr& Action, const JS::HandleValueArray& paramData) -{ - std::map >::iterator it = m_ScriptHandlers.find(Action); - if (it == m_ScriptHandlers.end()) - return; - - JSContext* cx = m_pGUI.GetScriptInterface()->GetContext(); - JSAutoRequest rq(cx); - JS::RootedObject obj(cx, GetJSObject()); - JS::RootedValue handlerVal(cx, JS::ObjectValue(*it->second)); - JS::RootedValue result(cx); - - if (!JS_CallFunctionValue(cx, obj, handlerVal, paramData, &result)) - JS_ReportError(cx, "Errors executing script action \"%s\"", Action.c_str()); -} - -void IGUIObject::CreateJSObject() -{ - JSContext* cx = m_pGUI.GetScriptInterface()->GetContext(); - JSAutoRequest rq(cx); - - m_JSObject.init(cx, m_pGUI.GetScriptInterface()->CreateCustomObject("GUIObject")); - JS_SetPrivate(m_JSObject.get(), this); - - RegisterScriptFunctions(); -} - -JSObject* IGUIObject::GetJSObject() -{ - // Cache the object when somebody first asks for it, because otherwise - // we end up doing far too much object allocation. - if (!m_JSObject.initialized()) - CreateJSObject(); - - return m_JSObject.get(); -} - -bool IGUIObject::IsEnabled() const -{ - return m_Enabled; -} - -bool IGUIObject::IsHidden() const -{ - return m_Hidden; -} - -bool IGUIObject::IsHiddenOrGhost() const -{ - return m_Hidden || m_Ghost; -} - -void IGUIObject::PlaySound(const CStrW& soundPath) const -{ - if (g_SoundManager && !soundPath.empty()) - g_SoundManager->PlayAsUI(soundPath.c_str(), false); -} - -CStr IGUIObject::GetPresentableName() const -{ - // __internal(), must be at least 13 letters to be able to be - // an internal name - if (m_Name.length() <= 12) - return m_Name; - - if (m_Name.substr(0, 10) == "__internal") - return CStr("[unnamed object]"); - else - return m_Name; -} - -void IGUIObject::SetFocus() -{ - m_pGUI.SetFocusedObject(this); -} - -bool IGUIObject::IsFocused() const -{ - return m_pGUI.GetFocusedObject() == this; -} - -bool IGUIObject::IsBaseObject() const -{ - return this == &m_pGUI.GetBaseObject(); -} - -bool IGUIObject::IsRootObject() const -{ - return m_pParent == &m_pGUI.GetBaseObject(); -} - -void IGUIObject::TraceMember(JSTracer* trc) -{ - // Please ensure to adapt the Tracer enabling and disabling in accordance with the GC things traced! - - for (std::pair>& handler : m_ScriptHandlers) - JS_CallObjectTracer(trc, &handler.second, "IGUIObject::m_ScriptHandlers"); -} - -// Instantiate templated functions: -// These functions avoid copies by working with a reference and move semantics. -#define TYPE(T) \ - template void IGUIObject::RegisterSetting(const CStr& Name, T& Value); \ - template T& IGUIObject::GetSetting(const CStr& Setting); \ - template const T& IGUIObject::GetSetting(const CStr& Setting) const; \ - template void IGUIObject::SetSetting(const CStr& Setting, T& Value, const bool SendMessage); \ - -#include "gui/GUItypes.h" -#undef TYPE - -// Copying functions - discouraged except for primitives. -#define TYPE(T) \ - template void IGUIObject::SetSetting(const CStr& Setting, const T& Value, const bool SendMessage); \ - -#define GUITYPE_IGNORE_NONCOPYABLE -#include "gui/GUItypes.h" -#undef GUITYPE_IGNORE_NONCOPYABLE -#undef TYPE Property changes on: ps/trunk/source/gui/IGUIObject.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/MiniMap.h =================================================================== --- ps/trunk/source/gui/MiniMap.h (revision 23027) +++ ps/trunk/source/gui/MiniMap.h (nonexistent) @@ -1,115 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_MINIMAP -#define INCLUDED_MINIMAP - -#include "gui/IGUIObject.h" -#include "graphics/ShaderProgramPtr.h" -#include "renderer/VertexArray.h" - -class CCamera; -class CMatrix3D; -class CTerrain; - -class CMiniMap : public IGUIObject -{ - GUI_OBJECT(CMiniMap) -public: - CMiniMap(CGUI& pGUI); - virtual ~CMiniMap(); -protected: - virtual void Draw(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * @see IGUIObject#IsMouseOver() - */ - virtual bool IsMouseOver() const; - - // create the minimap textures - void CreateTextures(); - - // rebuild the terrain texture map - void RebuildTerrainTexture(); - - // destroy and free any memory and textures - void Destroy(); - - void SetCameraPos(); - - void FireWorldClickEvent(int button, int clicks); - - // the terrain we are mini-mapping - const CTerrain* m_Terrain; - - const CCamera* m_Camera; - - //Whether or not the mouse is currently down - bool m_Clicking; - - // minimap texture handles - GLuint m_TerrainTexture; - - // texture data - u32* m_TerrainData; - - // whether we need to regenerate the terrain texture - bool m_TerrainDirty; - - ssize_t m_Width, m_Height; - - // map size - ssize_t m_MapSize; - - // texture size - GLsizei m_TextureSize; - - // 1.f if map is circular or 1.414f if square (to shrink it inside the circle) - float m_MapScale; - - // maximal water height to allow the passage of a unit (for underwater shallows). - float m_ShallowPassageHeight; - - float m_WaterHeight; - - void DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const; - - void DrawViewRect(CMatrix3D transform) const; - - void GetMouseWorldCoordinates(float& x, float& z) const; - - float GetAngle() const; - - VertexIndexArray m_IndexArray; - VertexArray m_VertexArray; - VertexArray::Attribute m_AttributePos; - VertexArray::Attribute m_AttributeColor; - - size_t m_EntitiesDrawn; - - double m_PingDuration; - double m_HalfBlinkDuration; - double m_NextBlinkTime; - bool m_BlinkState; -}; - -#endif // INCLUDED_MINIMAP Property changes on: ps/trunk/source/gui/MiniMap.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/COList.cpp =================================================================== --- ps/trunk/source/gui/COList.cpp (revision 23027) +++ ps/trunk/source/gui/COList.cpp (nonexistent) @@ -1,442 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "COList.h" - -#include "gui/CGUI.h" -#include "gui/CGUIColor.h" -#include "gui/CGUIList.h" -#include "gui/IGUIScrollBar.h" -#include "i18n/L10n.h" -#include "ps/CLogger.h" - -const float SORT_SPRITE_DIM = 16.0f; -const CPos COLUMN_SHIFT = CPos(0, 4); - -COList::COList(CGUI& pGUI) - : CList(pGUI), - m_SpriteHeading(), - m_Sortable(), - m_SelectedColumn(), - m_SelectedColumnOrder(), - m_SpriteAsc(), - m_SpriteDesc(), - m_SpriteNotSorted() -{ - RegisterSetting("sprite_heading", m_SpriteHeading); - RegisterSetting("sortable", m_Sortable); // The actual sorting is done in JS for more versatility - RegisterSetting("selected_column", m_SelectedColumn); - RegisterSetting("selected_column_order", m_SelectedColumnOrder); - RegisterSetting("sprite_asc", m_SpriteAsc); // Show the order of sorting - RegisterSetting("sprite_desc", m_SpriteDesc); - RegisterSetting("sprite_not_sorted", m_SpriteNotSorted); -} - -void COList::SetupText() -{ - m_ItemsYPositions.resize(m_List.m_Items.size() + 1); - - // Delete all generated texts. Some could probably be saved, - // but this is easier, and this function will never be called - // continuously, or even often, so it'll probably be okay. - m_GeneratedTexts.clear(); - - m_TotalAvailableColumnWidth = GetListRect().GetWidth(); - // remove scrollbar if applicable - if (m_ScrollBar && GetScrollBar(0).GetStyle()) - m_TotalAvailableColumnWidth -= GetScrollBar(0).GetStyle()->m_Width; - - m_HeadingHeight = SORT_SPRITE_DIM; // At least the size of the sorting sprite - - for (const COListColumn& column : m_Columns) - { - float width = column.m_Width; - if (column.m_Width > 0 && column.m_Width < 1) - width *= m_TotalAvailableColumnWidth; - - CGUIString gui_string; - gui_string.SetValue(column.m_Heading); - - const CGUIText& text = AddText(gui_string, m_Font, width, m_BufferZone); - m_HeadingHeight = std::max(m_HeadingHeight, text.GetSize().cy + COLUMN_SHIFT.y); - } - - // Generate texts - float buffered_y = 0.f; - - for (size_t i = 0; i < m_List.m_Items.size(); ++i) - { - m_ItemsYPositions[i] = buffered_y; - float shift = 0.0f; - for (const COListColumn& column : m_Columns) - { - float width = column.m_Width; - if (column.m_Width > 0 && column.m_Width < 1) - width *= m_TotalAvailableColumnWidth; - - CGUIText* text; - if (!column.m_List.m_Items[i].GetOriginalString().empty()) - text = &AddText(column.m_List.m_Items[i], m_Font, width, m_BufferZone); - else - { - // Minimum height of a space character of the current font size - CGUIString align_string; - align_string.SetValue(L" "); - text = &AddText(align_string, m_Font, width, m_BufferZone); - } - shift = std::max(shift, text->GetSize().cy); - } - buffered_y += shift; - } - - m_ItemsYPositions[m_List.m_Items.size()] = buffered_y; - - if (m_ScrollBar) - { - CRect rect = GetListRect(); - GetScrollBar(0).SetScrollRange(m_ItemsYPositions.back()); - GetScrollBar(0).SetScrollSpace(rect.GetHeight()); - - GetScrollBar(0).SetX(rect.right); - GetScrollBar(0).SetY(rect.top); - GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(rect.bottom - rect.top); - } -} - -CRect COList::GetListRect() const -{ - return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0); -} - -void COList::HandleMessage(SGUIMessage& Message) -{ - CList::HandleMessage(Message); - - switch (Message.type) - { - // If somebody clicks on the column heading - case GUIM_MOUSE_PRESS_LEFT: - { - if (!m_Sortable) - return; - - const CPos& mouse = m_pGUI.GetMousePos(); - if (!m_CachedActualSize.PointInside(mouse)) - return; - - float xpos = 0; - for (const COListColumn& column : m_Columns) - { - if (column.m_Hidden) - continue; - - float width = column.m_Width; - // Check if it's a decimal value, and if so, assume relative positioning. - if (column.m_Width < 1 && column.m_Width > 0) - width *= m_TotalAvailableColumnWidth; - CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0); - if (mouse.x >= leftTopCorner.x && - mouse.x < leftTopCorner.x + width && - mouse.y < leftTopCorner.y + m_HeadingHeight) - { - if (column.m_Id != m_SelectedColumn) - { - SetSetting("selected_column_order", -1, true); - CStr selected_column = column.m_Id; - SetSetting("selected_column", selected_column, true); - } - else - SetSetting("selected_column_order", -m_SelectedColumnOrder, true); - - ScriptEvent("selectioncolumnchange"); - PlaySound(m_SoundSelected); - return; - } - xpos += width; - } - return; - } - default: - return; - } -} - -bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile) -{ - #define ELMT(x) int elmt_##x = pFile->GetElementID(#x) - #define ATTR(x) int attr_##x = pFile->GetAttributeID(#x) - ELMT(item); - ELMT(column); - ELMT(translatableAttribute); - ATTR(id); - ATTR(context); - - if (child.GetNodeName() == elmt_item) - { - AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8()); - return true; - } - else if (child.GetNodeName() == elmt_column) - { - COListColumn column; - - for (XMBAttribute attr : child.GetAttributes()) - { - CStr attr_name(pFile->GetAttributeString(attr.Name)); - CStr attr_value(attr.Value); - - if (attr_name == "color") - { - if (!CGUI::ParseString(&m_pGUI, attr_value.FromUTF8(), column.m_TextColor)) - LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str()); - } - else if (attr_name == "id") - { - column.m_Id = attr_value; - } - else if (attr_name == "hidden") - { - bool hidden = false; - if (!CGUI::ParseString(&m_pGUI, attr_value.FromUTF8(), hidden)) - LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str()); - else - column.m_Hidden = hidden; - } - else if (attr_name == "width") - { - float width; - if (!CGUI::ParseString(&m_pGUI, attr_value.FromUTF8(), width)) - LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str()); - else - { - // Check if it's a relative value, and save as decimal if so. - if (attr_value.find("%") != std::string::npos) - width = width / 100.f; - column.m_Width = width; - } - } - else if (attr_name == "heading") - { - column.m_Heading = attr_value.FromUTF8(); - } - } - - for (XMBElement grandchild : child.GetChildNodes()) - { - if (grandchild.GetNodeName() != elmt_translatableAttribute) - continue; - - CStr attributeName(grandchild.GetAttributes().GetNamedItem(attr_id)); - // only the heading is translatable for list column - if (attributeName.empty() || attributeName != "heading") - { - LOGERROR("GUI: translatable attribute in olist column that isn't a heading. (object: %s)", this->GetPresentableName().c_str()); - continue; - } - - CStr value(grandchild.GetText()); - if (value.empty()) - continue; - - CStr context(grandchild.GetAttributes().GetNamedItem(attr_context)); // Read the context if any. - if (!context.empty()) - { - CStr translatedValue(g_L10n.TranslateWithContext(context, value)); - column.m_Heading = translatedValue.FromUTF8(); - } - else - { - CStr translatedValue(g_L10n.Translate(value)); - column.m_Heading = translatedValue.FromUTF8(); - } - } - - m_Columns.emplace_back(std::move(column)); - return true; - } - - return false; -} - -void COList::AdditionalChildrenHandled() -{ - SetupText(); - - // Do this after the last push_back call to avoid iterator invalidation - for (COListColumn& column : m_Columns) - { - RegisterSetting("list_" + column.m_Id, column.m_List); - RegisterSetting("hidden_" + column.m_Id, column.m_Hidden); - } -} - -void COList::DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor) -{ - const float bz = GetBufferedZ(); - - if (m_ScrollBar) - IGUIScrollBarOwner::Draw(); - - CRect rect = GetListRect(); - - m_pGUI.DrawSprite(sprite, m_CellID, bz, rect); - - float scroll = 0.f; - if (m_ScrollBar) - scroll = GetScrollBar(0).GetPos(); - - // Draw item selection - if (selected != -1) - { - ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size()); - - // Get rectangle of selection: - CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, - rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll); - - if (rect_sel.top <= rect.bottom && - rect_sel.bottom >= rect.top) - { - if (rect_sel.bottom > rect.bottom) - rect_sel.bottom = rect.bottom; - if (rect_sel.top < rect.top) - rect_sel.top = rect.top; - - if (m_ScrollBar) - { - // Remove any overlapping area of the scrollbar. - if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && - rect_sel.right <= GetScrollBar(0).GetOuterRect().right) - rect_sel.right = GetScrollBar(0).GetOuterRect().left; - - if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && - rect_sel.left < GetScrollBar(0).GetOuterRect().right) - rect_sel.left = GetScrollBar(0).GetOuterRect().right; - } - - // Draw item selection - m_pGUI.DrawSprite(sprite_selected, m_CellID, bz + 0.05f, rect_sel); - } - } - - // Draw line above column header - CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right, - m_CachedActualSize.top + m_HeadingHeight); - m_pGUI.DrawSprite(m_SpriteHeading, m_CellID, bz, rect_head); - - // Draw column headers - float xpos = 0; - size_t col = 0; - for (const COListColumn& column : m_Columns) - { - if (column.m_Hidden) - { - ++col; - continue; - } - - // Check if it's a decimal value, and if so, assume relative positioning. - float width = column.m_Width; - if (column.m_Width < 1 && column.m_Width > 0) - width *= m_TotalAvailableColumnWidth; - - CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0); - - // Draw sort arrows in colum header - if (m_Sortable) - { - const CGUISpriteInstance* sprite; - if (m_SelectedColumn == column.m_Id) - { - if (m_SelectedColumnOrder == 0) - LOGERROR("selected_column_order must not be 0"); - - if (m_SelectedColumnOrder != -1) - sprite = &m_SpriteAsc; - else - sprite = &m_SpriteDesc; - } - else - sprite = &m_SpriteNotSorted; - - m_pGUI.DrawSprite(*sprite, m_CellID, bz + 0.1f, CRect(leftTopCorner + CPos(width - SORT_SPRITE_DIM, 0), leftTopCorner + CPos(width, SORT_SPRITE_DIM))); - } - - // Draw column header text - DrawText(col, textcolor, leftTopCorner + COLUMN_SHIFT, bz + 0.1f, rect_head); - xpos += width; - ++col; - } - - // Draw list items for each column - const size_t objectsCount = m_Columns.size(); - for (size_t i = 0; i < m_List.m_Items.size(); ++i) - { - if (m_ItemsYPositions[i+1] - scroll < 0 || - m_ItemsYPositions[i] - scroll > rect.GetHeight()) - continue; - - const float rowHeight = m_ItemsYPositions[i+1] - m_ItemsYPositions[i]; - - // Clipping area (we'll have to substract the scrollbar) - CRect cliparea = GetListRect(); - - if (m_ScrollBar) - { - if (cliparea.right > GetScrollBar(0).GetOuterRect().left && - cliparea.right <= GetScrollBar(0).GetOuterRect().right) - cliparea.right = GetScrollBar(0).GetOuterRect().left; - - if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && - cliparea.left < GetScrollBar(0).GetOuterRect().right) - cliparea.left = GetScrollBar(0).GetOuterRect().right; - } - - // Draw all items for that column - xpos = 0; - size_t col = 0; - for (const COListColumn& column : m_Columns) - { - if (column.m_Hidden) - { - ++col; - continue; - } - - // Determine text position and width - const CPos textPos = rect.TopLeft() + CPos(xpos, -scroll + m_ItemsYPositions[i]); - - float width = column.m_Width; - // Check if it's a decimal value, and if so, assume relative positioning. - if (column.m_Width < 1 && column.m_Width > 0) - width *= m_TotalAvailableColumnWidth; - - // Clip text to the column (to prevent drawing text into the neighboring column) - CRect cliparea2 = cliparea; - cliparea2.right = std::min(cliparea2.right, textPos.x + width); - cliparea2.bottom = std::min(cliparea2.bottom, textPos.y + rowHeight); - - // Draw list item - DrawText(objectsCount * (i +/*Heading*/1) + col, column.m_TextColor, textPos, bz + 0.1f, cliparea2); - xpos += width; - ++col; - } - } -} Property changes on: ps/trunk/source/gui/COList.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUISize.h =================================================================== --- ps/trunk/source/gui/CGUISize.h (revision 23027) +++ ps/trunk/source/gui/CGUISize.h (nonexistent) @@ -1,83 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CGUISIZE -#define INCLUDED_CGUISIZE - -#include "ps/CStr.h" -#include "ps/Errors.h" -#include "ps/Shapes.h" -#include "scriptinterface/ScriptInterface.h" - -/** - * This class represents a rectangle relative to a parent rectangle - * The value can be initialized from a string or JS object. - */ -class CGUISize -{ -public: - // COPYABLE, since there are only primitives involved, making move and copy identical, - // and since some temporaries cannot be avoided. - CGUISize(); - CGUISize(const CRect& pixel, const CRect& percent); - - static CGUISize Full(); - - /// Pixel modifiers - CRect pixel; - - /// Percent modifiers - CRect percent; - - /** - * Get client area rectangle when the parent is given - */ - CRect GetSize(const CRect& parent) const; - - /** - * The value can be set from a string looking like: - * - * "0 0 100% 100%" - * "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 - * though that the percent modifier must always be the first when - * both modifiers are inputted. - * - * @return true if success, otherwise size will remain unchanged. - */ - bool FromString(const CStr& Value); - - bool operator==(const CGUISize& other) const - { - return pixel == other.pixel && percent == other.percent; - } - - void ToJSVal(JSContext* cx, JS::MutableHandleValue ret) const; - bool FromJSVal(JSContext* cx, JS::HandleValue v); -}; - - -ERROR_GROUP(GUI); - -ERROR_TYPE(GUI, InvalidSetting); -ERROR_TYPE(GUI, OperationNeedsGUIObject); -ERROR_TYPE(GUI, NameAmbiguity); -ERROR_TYPE(GUI, ObjectNeedsName); - -#endif // INCLUDED_CGUISIZE Property changes on: ps/trunk/source/gui/CGUISize.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CCheckBox.cpp =================================================================== --- ps/trunk/source/gui/CCheckBox.cpp (revision 23027) +++ ps/trunk/source/gui/CCheckBox.cpp (nonexistent) @@ -1,87 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CCheckBox.h" - -#include "gui/CGUI.h" - -CCheckBox::CCheckBox(CGUI& pGUI) - : IGUIObject(pGUI), - IGUIButtonBehavior(*static_cast(this)), - m_CellID(), - m_Checked(), - m_SpriteUnchecked(), - m_SpriteUncheckedOver(), - m_SpriteUncheckedPressed(), - m_SpriteUncheckedDisabled(), - m_SpriteChecked(), - m_SpriteCheckedOver(), - m_SpriteCheckedPressed(), - m_SpriteCheckedDisabled() -{ - RegisterSetting("cell_id", m_CellID); - RegisterSetting("checked", m_Checked), - RegisterSetting("sprite", m_SpriteUnchecked); - RegisterSetting("sprite_over", m_SpriteUncheckedOver); - RegisterSetting("sprite_pressed", m_SpriteUncheckedPressed); - RegisterSetting("sprite_disabled", m_SpriteUncheckedDisabled); - RegisterSetting("sprite2", m_SpriteChecked); - RegisterSetting("sprite2_over", m_SpriteCheckedOver); - RegisterSetting("sprite2_pressed", m_SpriteCheckedPressed); - RegisterSetting("sprite2_disabled", m_SpriteCheckedDisabled); -} - -CCheckBox::~CCheckBox() -{ -} - -void CCheckBox::ResetStates() -{ - IGUIObject::ResetStates(); - IGUIButtonBehavior::ResetStates(); -} - -void CCheckBox::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - IGUIButtonBehavior::HandleMessage(Message); - - switch (Message.type) - { - case GUIM_PRESSED: - { - SetSetting("checked", !m_Checked, true); - break; - } - - default: - break; - } -} - -void CCheckBox::Draw() -{ - m_pGUI.DrawSprite( - m_Checked ? - GetButtonSprite(m_SpriteChecked, m_SpriteCheckedOver, m_SpriteCheckedPressed, m_SpriteCheckedDisabled) : - GetButtonSprite(m_SpriteUnchecked, m_SpriteUncheckedOver, m_SpriteUncheckedPressed, m_SpriteUncheckedDisabled), - m_CellID, - GetBufferedZ(), - m_CachedActualSize); -} Property changes on: ps/trunk/source/gui/CCheckBox.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CImage.cpp =================================================================== --- ps/trunk/source/gui/CImage.cpp (revision 23027) +++ ps/trunk/source/gui/CImage.cpp (nonexistent) @@ -1,40 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CImage.h" - -#include "gui/CGUI.h" - -CImage::CImage(CGUI& pGUI) - : IGUIObject(pGUI), - m_Sprite(), - m_CellID() -{ - RegisterSetting("sprite", m_Sprite); - RegisterSetting("cell_id", m_CellID); -} - -CImage::~CImage() -{ -} - -void CImage::Draw() -{ - m_pGUI.DrawSprite(m_Sprite, m_CellID, GetBufferedZ(), m_CachedActualSize); -} Property changes on: ps/trunk/source/gui/CImage.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUIDummyObject.h =================================================================== --- ps/trunk/source/gui/CGUIDummyObject.h (revision 23027) +++ ps/trunk/source/gui/CGUIDummyObject.h (nonexistent) @@ -1,49 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* - * This is the top class of the whole GUI, all objects - * and settings are stored within this class. - */ - -#ifndef INCLUDED_CGUIDUMMYOBJECT -#define INCLUDED_CGUIDUMMYOBJECT - -#include "gui/IGUIObject.h" - -/** - * Dummy object are used for the base object and objects of type "empty". - */ -class CGUIDummyObject : public IGUIObject -{ - GUI_OBJECT(CGUIDummyObject) - -public: - CGUIDummyObject(CGUI& pGUI) : IGUIObject(pGUI) {} - - virtual void Draw() {} - - /** - * Empty can never be hovered. It is only a category. - */ - virtual bool IsMouseOver() const - { - return false; - } -}; - -#endif // INCLUDED_CGUIDUMMYOBJECT Property changes on: ps/trunk/source/gui/CGUIDummyObject.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUIColor.cpp =================================================================== --- ps/trunk/source/gui/CGUIColor.cpp (revision 23027) +++ ps/trunk/source/gui/CGUIColor.cpp (nonexistent) @@ -1,40 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CGUIColor.h" - -#include "gui/CGUI.h" -#include "ps/CStr.h" - -bool CGUIColor::ParseString(const CGUI& pGUI, const CStr& value, int defaultAlpha) -{ - if (pGUI.HasPreDefinedColor(value)) - { - const CGUIColor& color = pGUI.GetPreDefinedColor(value); - - // Explicit copy assignment - r = color.r; - g = color.g; - b = color.b; - a = color.a; - return true; - } - - return CColor::ParseString(value, defaultAlpha); -} Property changes on: ps/trunk/source/gui/CGUIColor.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUITextOwner.cpp =================================================================== --- ps/trunk/source/gui/IGUITextOwner.cpp (revision 23027) +++ ps/trunk/source/gui/IGUITextOwner.cpp (nonexistent) @@ -1,126 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "IGUITextOwner.h" - -#include "gui/CGUI.h" -#include "gui/CGUIString.h" - -#include - -IGUITextOwner::IGUITextOwner(IGUIObject& pObject) - : m_pObject(pObject), - m_GeneratedTextsValid() -{ -} - -IGUITextOwner::~IGUITextOwner() -{ -} - -CGUIText& IGUITextOwner::AddText() -{ - m_GeneratedTexts.emplace_back(); - return m_GeneratedTexts.back(); -} - -CGUIText& IGUITextOwner::AddText(const CGUIString& Text, const CStrW& Font, const float& Width, const float& BufferZone) -{ - // Avoids a move constructor - m_GeneratedTexts.emplace_back(m_pObject.GetGUI(), Text, Font, Width, BufferZone, &m_pObject); - return m_GeneratedTexts.back(); -} - -void IGUITextOwner::HandleMessage(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. Although that is not certain, but one will have to manually - // change it and disregard this function. - // TODO Gee: (2004-09-07) Make sure this is all options that can affect the text. - if (Message.value == "size" || Message.value == "z" || - Message.value == "absolute" || Message.value == "caption" || - Message.value == "font" || Message.value == "textcolor" || - Message.value == "text_align" || Message.value == "text_valign" || - Message.value == "buffer_zone") - { - m_GeneratedTextsValid = false; - } - break; - - default: - break; - } -} - -void IGUITextOwner::UpdateCachedSize() -{ - // update our text positions - m_GeneratedTextsValid = false; -} - -void IGUITextOwner::UpdateText() -{ - if (!m_GeneratedTextsValid) - { - SetupText(); - m_GeneratedTextsValid = true; - } -} - -void IGUITextOwner::DrawText(size_t index, const CGUIColor& color, const CPos& pos, float z, const CRect& clipping) -{ - UpdateText(); - - ENSURE(index < m_GeneratedTexts.size() && "Trying to draw a Text Index within a IGUITextOwner that doesn't exist"); - - m_GeneratedTexts.at(index).Draw(m_pObject.GetGUI(), color, pos, z, clipping); -} - -void IGUITextOwner::CalculateTextPosition(CRect& ObjSize, CPos& TextPos, CGUIText& Text) -{ - // The horizontal Alignment is now computed in GenerateText in order to not have to - // loop through all of the TextCall objects again. - TextPos.x = ObjSize.left; - - switch (m_pObject.GetSetting("text_valign")) - { - case EVAlign_Top: - TextPos.y = ObjSize.top; - break; - case EVAlign_Center: - // Round to integer pixel values, else the fonts look awful - TextPos.y = floorf(ObjSize.CenterPoint().y - Text.GetSize().cy / 2.f); - break; - case EVAlign_Bottom: - TextPos.y = ObjSize.bottom - Text.GetSize().cy; - break; - default: - debug_warn(L"Broken EVAlign in CButton::SetupText()"); - break; - } -} - -bool IGUITextOwner::MouseOverIcon() -{ - return false; -} Property changes on: ps/trunk/source/gui/IGUITextOwner.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CProgressBar.cpp =================================================================== --- ps/trunk/source/gui/CProgressBar.cpp (revision 23027) +++ ps/trunk/source/gui/CProgressBar.cpp (nonexistent) @@ -1,73 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CProgressBar.h" - -#include "gui/CGUI.h" - -CProgressBar::CProgressBar(CGUI& pGUI) - : IGUIObject(pGUI), - m_SpriteBackground(), - m_SpriteBar(), - m_Caption() -{ - RegisterSetting("sprite_background", m_SpriteBackground); - RegisterSetting("sprite_bar", m_SpriteBar); - RegisterSetting("caption", m_Caption); // aka value from 0 to 100 -} - -CProgressBar::~CProgressBar() -{ -} - -void CProgressBar::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - // Update scroll-bar - // TODO Gee: (2004-09-01) Is this really updated each time it should? - if (Message.value == "caption") - { - if (m_Caption > 100.f) - SetSetting("caption", 100.f, true); - else if (m_Caption < 0.f) - SetSetting("caption", 0.f, true); - } - break; - default: - break; - } -} - -void CProgressBar::Draw() -{ - float bz = GetBufferedZ(); - - int cell_id = 0; - - m_pGUI.DrawSprite(m_SpriteBackground, cell_id, bz, m_CachedActualSize); - - // Get size of bar (notice it is drawn slightly closer, to appear above the background) - CRect bar_size(m_CachedActualSize.left, m_CachedActualSize.top, - m_CachedActualSize.left+m_CachedActualSize.GetWidth()*(m_Caption/100.f), m_CachedActualSize.bottom); - m_pGUI.DrawSprite(m_SpriteBar, cell_id, bz+0.01f, bar_size); -} Property changes on: ps/trunk/source/gui/CProgressBar.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CText.h =================================================================== --- ps/trunk/source/gui/CText.h (revision 23027) +++ ps/trunk/source/gui/CText.h (nonexistent) @@ -1,102 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CTEXT -#define INCLUDED_CTEXT - -#include "gui/CGUISprite.h" -#include "gui/CGUIString.h" -#include "gui/IGUIScrollBarOwner.h" -#include "gui/IGUITextOwner.h" - -/** - * Text field that just displays static text. - */ -class CText : public IGUIObject, public IGUIScrollBarOwner, public IGUITextOwner -{ - GUI_OBJECT(CText) - -public: - CText(CGUI& pGUI); - virtual ~CText(); - - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - /** - * @see IGUIObject#UpdateCachedSize() - */ - virtual void UpdateCachedSize(); - - /** - * Test if mouse position is over an icon - */ - virtual bool MouseOverIcon(); - -protected: - /** - * Sets up text, should be called every time changes has been - * made that can change the visual. - */ - void SetupText(); - - virtual void RegisterScriptFunctions(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * Draws the Text - */ - virtual void Draw(); - - /** - * Script accessors to this GUI object. - */ - static JSFunctionSpec JSI_methods[]; - - static bool GetTextSize(JSContext* cx, uint argc, JS::Value* vp); - - /** - * Placement of text. Ignored when scrollbars are active. - */ - CPos m_TextPos; - - // Settings - float m_BufferZone; - CGUIString m_Caption; - i32 m_CellID; - bool m_Clip; - CStrW m_Font; - bool m_ScrollBar; - CStr m_ScrollBarStyle; - bool m_ScrollBottom; - bool m_ScrollTop; - CGUISpriteInstance m_Sprite; - EAlign m_TextAlign; - EVAlign m_TextVAlign; - CGUIColor m_TextColor; - CGUIColor m_TextColorDisabled; - CStrW m_IconTooltip; - CStr m_IconTooltipStyle; -}; - -#endif // INCLUDED_CTEXT Property changes on: ps/trunk/source/gui/CText.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUIButtonBehavior.h =================================================================== --- ps/trunk/source/gui/IGUIButtonBehavior.h (revision 23027) +++ ps/trunk/source/gui/IGUIButtonBehavior.h (nonexistent) @@ -1,93 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* - Interface class that enhance the IGUIObject with - buttony behavior (click and release to click a button), - and the GUI message GUIM_PRESSED. - When creating a class with extended settings and - buttony behavior, just do a multiple inheritance. -*/ - -#ifndef INCLUDED_IGUIBUTTONBEHAVIOR -#define INCLUDED_IGUIBUTTONBEHAVIOR - -#include "gui/IGUIObject.h" - -class CGUISpriteInstance; - -/** - * Appends button behaviours to the IGUIObject. - * Can be used with multiple inheritance alongside - * IGUISettingsObject and such. - */ -class IGUIButtonBehavior -{ - NONCOPYABLE(IGUIButtonBehavior); - -public: - IGUIButtonBehavior(IGUIObject& pObject); - virtual ~IGUIButtonBehavior(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * This is a function that lets a button being drawn, - * it regards if it's over, disabled, pressed and such. - * - * @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 - */ - const CGUISpriteInstance& GetButtonSprite(const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_over, const CGUISpriteInstance& sprite_pressed, const CGUISpriteInstance& sprite_disabled) const; - -protected: - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - /** - * Everybody knows how a button works, you don't simply press it, - * you have to first press the button, and then release it... - * in between those two steps you can actually leave the button - * area, as long as you release it within the button area... Anyway - * this lets us know we are done with step one (clicking). - */ - bool m_Pressed; - bool m_PressedRight; - - // Settings - CStrW m_SoundDisabled; - CStrW m_SoundEnter; - CStrW m_SoundLeave; - CStrW m_SoundPressed; - CStrW m_SoundReleased; - -private: - /** - * Reference to the IGUIObject. - * Private, because we don't want to inherit it in multiple classes. - */ - IGUIObject& m_pObject; -}; - -#endif // INCLUDED_IGUIBUTTONBEHAVIOR Property changes on: ps/trunk/source/gui/IGUIButtonBehavior.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CButton.cpp =================================================================== --- ps/trunk/source/gui/CButton.cpp (revision 23027) +++ ps/trunk/source/gui/CButton.cpp (nonexistent) @@ -1,119 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CButton.h" - -#include "gui/CGUI.h" -#include "gui/CGUIColor.h" -#include "gui/CGUIText.h" - -CButton::CButton(CGUI& pGUI) - : IGUIObject(pGUI), - IGUIButtonBehavior(*static_cast(this)), - IGUITextOwner(*static_cast(this)), - m_BufferZone(), - m_CellID(), - m_Caption(), - m_Font(), - m_Sprite(), - m_SpriteOver(), - m_SpritePressed(), - m_SpriteDisabled(), - m_TextAlign(), - m_TextVAlign(), - m_TextColor(), - m_TextColorOver(), - m_TextColorPressed(), - m_TextColorDisabled() -{ - RegisterSetting("buffer_zone", m_BufferZone); - RegisterSetting("cell_id", m_CellID); - RegisterSetting("caption", m_Caption); - RegisterSetting("font", m_Font); - RegisterSetting("sprite", m_Sprite); - RegisterSetting("sprite_over", m_SpriteOver); - RegisterSetting("sprite_pressed", m_SpritePressed); - RegisterSetting("sprite_disabled", m_SpriteDisabled); - RegisterSetting("text_align", m_TextAlign); - RegisterSetting("text_valign", m_TextVAlign); - RegisterSetting("textcolor", m_TextColor); - RegisterSetting("textcolor_over", m_TextColorOver); - RegisterSetting("textcolor_pressed", m_TextColorPressed); - RegisterSetting("textcolor_disabled", m_TextColorDisabled); - - AddText(); -} - -CButton::~CButton() -{ -} - -void CButton::SetupText() -{ - ENSURE(m_GeneratedTexts.size() == 1); - - m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_CachedActualSize.GetWidth(), m_BufferZone, this); - CalculateTextPosition(m_CachedActualSize, m_TextPos, m_GeneratedTexts[0]); -} - -void CButton::ResetStates() -{ - IGUIObject::ResetStates(); - IGUIButtonBehavior::ResetStates(); -} - -void CButton::UpdateCachedSize() -{ - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); -} - -void CButton::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - IGUIButtonBehavior::HandleMessage(Message); - IGUITextOwner::HandleMessage(Message); -} - -void CButton::Draw() -{ - const float bz = GetBufferedZ(); - - m_pGUI.DrawSprite( - GetButtonSprite(m_Sprite, m_SpriteOver, m_SpritePressed, m_SpriteDisabled), - m_CellID, - bz, - m_CachedActualSize); - - DrawText(0, ChooseColor(), m_TextPos, bz + 0.1f); -} - -const CGUIColor& CButton::ChooseColor() -{ - if (!m_Enabled) - return m_TextColorDisabled || m_TextColor; - - if (!m_MouseHovering) - return m_TextColor; - - if (m_Pressed) - return m_TextColorPressed || m_TextColor; - - return m_TextColorOver || m_TextColor; -} Property changes on: ps/trunk/source/gui/CButton.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUITextOwner.h =================================================================== --- ps/trunk/source/gui/IGUITextOwner.h (revision 23027) +++ ps/trunk/source/gui/IGUITextOwner.h (nonexistent) @@ -1,123 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* -GUI Object Base - Text Owner - ---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. -*/ - -#ifndef INCLUDED_IGUITEXTOWNER -#define INCLUDED_IGUITEXTOWNER - -#include "gui/IGUIObject.h" - -#include - -struct CGUIColor; -class CGUIText; -class CGUIString; - -/** - * Framework for handling Output text. - */ -class IGUITextOwner -{ - NONCOPYABLE(IGUITextOwner); - -public: - IGUITextOwner(IGUIObject& pObject); - virtual ~IGUITextOwner(); - - /** - * Adds a text object. - */ - CGUIText& AddText(); - - /** - * Adds a text generated by the given arguments. - */ - CGUIText& AddText(const CGUIString& Text, const CStrW& Font, const float& Width, const float& BufferZone); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * @see IGUIObject#UpdateCachedSize() - */ - virtual void UpdateCachedSize(); - - /** - * Draws the Text. - * - * @param index Index value of text. Mostly this will be 0 - * @param color - * @param pos Position - * @param z Z value - * @param clipping Clipping rectangle, don't even add a parameter - * to get no clipping. - */ - virtual void DrawText(size_t index, const CGUIColor& color, const CPos& pos, float z, const CRect& clipping = CRect()); - - /** - * Test if mouse position is over an icon - */ - virtual bool MouseOverIcon(); - -protected: - /** - * Setup texts. Functions that sets up all texts when changes have been made. - */ - virtual void SetupText() = 0; - - /** - * Regenerate the text in case it is invalid. Should only be called when inevitable. - */ - virtual void UpdateText(); - - /** - * Whether the cached text is currently valid (if not then SetupText will be called by Draw) - */ - bool m_GeneratedTextsValid; - - /** - * Texts that are generated and ready to be rendered. - */ - std::vector m_GeneratedTexts; - - /** - * Calculate the position for the text, based on the alignment. - */ - void CalculateTextPosition(CRect& ObjSize, CPos& TextPos, CGUIText& Text); - -private: - /** - * Reference to the IGUIObject. - * Private, because we don't want to inherit it in multiple classes. - */ - IGUIObject& m_pObject; -}; - -#endif // INCLUDED_IGUITEXTOWNER Property changes on: ps/trunk/source/gui/IGUITextOwner.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUIScrollBarOwner.h =================================================================== --- ps/trunk/source/gui/IGUIScrollBarOwner.h (revision 23027) +++ ps/trunk/source/gui/IGUIScrollBarOwner.h (nonexistent) @@ -1,94 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_IGUISCROLLBAROWNER -#define INCLUDED_IGUISCROLLBAROWNER - -#include "gui/IGUIObject.h" - -#include - -struct SGUIScrollBarStyle; -class IGUIScrollBar; - -/** - * Base-class this if you want an object to contain - * one, or several, scroll-bars. - */ -class IGUIScrollBarOwner -{ - NONCOPYABLE(IGUIScrollBarOwner); - - friend class IGUIScrollBar; - -public: - IGUIScrollBarOwner(IGUIObject& m_pObject); - virtual ~IGUIScrollBarOwner(); - - virtual void Draw(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - /** - * Interface for the m_ScrollBar to use. - */ - virtual const SGUIScrollBarStyle* GetScrollBarStyle(const CStr& style) const; - - /** - * Add a scroll-bar - */ - virtual void AddScrollBar(IGUIScrollBar* scrollbar); - - /** - * Get Scroll Bar reference (it should be transparent it's actually - * pointers). - */ - virtual IGUIScrollBar& GetScrollBar(const int& index) - { - return *m_ScrollBars[index]; - } - - /** - * Get the position of the scroll bar at @param index. - * Equivalent to GetScrollbar(index).GetPos(). - */ - virtual float GetScrollBarPos(const int index) const; - -protected: - /** - * Predominately you will only have one, but you can have - * as many as you like. - */ - std::vector m_ScrollBars; - -private: - /** - * Reference to the IGUIObject. - * Private, because we don't want to inherit it in multiple classes. - */ - IGUIObject& m_pObject; -}; - -#endif // INCLUDED_IGUISCROLLBAROWNER Property changes on: ps/trunk/source/gui/IGUIScrollBarOwner.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/ScriptFunctions.cpp =================================================================== --- ps/trunk/source/gui/scripting/ScriptFunctions.cpp (revision 23027) +++ ps/trunk/source/gui/scripting/ScriptFunctions.cpp (nonexistent) @@ -1,75 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "ScriptFunctions.h" - -#include "graphics/scripting/JSInterface_GameView.h" -#include "gui/scripting/JSInterface_GUIManager.h" -#include "gui/scripting/JSInterface_GUISize.h" -#include "gui/scripting/JSInterface_IGUIObject.h" -#include "i18n/scripting/JSInterface_L10n.h" -#include "lobby/scripting/JSInterface_Lobby.h" -#include "network/scripting/JSInterface_Network.h" -#include "ps/scripting/JSInterface_ConfigDB.h" -#include "ps/scripting/JSInterface_Console.h" -#include "ps/scripting/JSInterface_Debug.h" -#include "ps/scripting/JSInterface_Game.h" -#include "ps/scripting/JSInterface_Main.h" -#include "ps/scripting/JSInterface_Mod.h" -#include "ps/scripting/JSInterface_ModIo.h" -#include "ps/scripting/JSInterface_SavedGame.h" -#include "ps/scripting/JSInterface_UserReport.h" -#include "ps/scripting/JSInterface_VFS.h" -#include "ps/scripting/JSInterface_VisualReplay.h" -#include "renderer/scripting/JSInterface_Renderer.h" -#include "scriptinterface/ScriptInterface.h" -#include "simulation2/scripting/JSInterface_Simulation.h" -#include "soundmanager/scripting/JSInterface_Sound.h" - -/* - * This file defines a set of functions that are available to GUI scripts, to allow - * interaction with the rest of the engine. - * Functions are exposed to scripts within the global object 'Engine', so - * scripts should call "Engine.FunctionName(...)" etc. - */ -void GuiScriptingInit(ScriptInterface& scriptInterface) -{ - JSI_GUISize::RegisterScriptClass(scriptInterface); - JSI_IGUIObject::RegisterScriptClass(scriptInterface); - - JSI_ConfigDB::RegisterScriptFunctions(scriptInterface); - JSI_Console::RegisterScriptFunctions(scriptInterface); - JSI_Debug::RegisterScriptFunctions(scriptInterface); - JSI_GUIManager::RegisterScriptFunctions(scriptInterface); - JSI_Game::RegisterScriptFunctions(scriptInterface); - JSI_GameView::RegisterScriptFunctions(scriptInterface); - JSI_L10n::RegisterScriptFunctions(scriptInterface); - JSI_Lobby::RegisterScriptFunctions(scriptInterface); - JSI_Main::RegisterScriptFunctions(scriptInterface); - JSI_Mod::RegisterScriptFunctions(scriptInterface); - JSI_ModIo::RegisterScriptFunctions(scriptInterface); - JSI_Network::RegisterScriptFunctions(scriptInterface); - JSI_Renderer::RegisterScriptFunctions(scriptInterface); - JSI_SavedGame::RegisterScriptFunctions(scriptInterface); - JSI_Simulation::RegisterScriptFunctions(scriptInterface); - JSI_Sound::RegisterScriptFunctions(scriptInterface); - JSI_UserReport::RegisterScriptFunctions(scriptInterface); - JSI_VFS::RegisterScriptFunctions_GUI(scriptInterface); - JSI_VisualReplay::RegisterScriptFunctions(scriptInterface); -} Property changes on: ps/trunk/source/gui/scripting/ScriptFunctions.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/JSInterface_GUIManager.h =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_GUIManager.h (revision 23027) +++ ps/trunk/source/gui/scripting/JSInterface_GUIManager.h (nonexistent) @@ -1,40 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_JSI_GUIMANAGER -#define INCLUDED_JSI_GUIMANAGER - -#include "scriptinterface/ScriptInterface.h" -#include "simulation2/system/ParamNode.h" - -namespace JSI_GUIManager -{ - void PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction); - void SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData); - void PopGuiPage(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue args); - JS::Value GetGUIObjectByName(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name); - void SetGlobalHotkey(ScriptInterface::CxPrivate* pCxPrivate, const std::string& hotkeyTag, JS::HandleValue function); - void UnsetGlobalHotkey(ScriptInterface::CxPrivate* pCxPrivate, const std::string& hotkeyTag); - std::wstring SetCursor(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name); - void ResetCursor(ScriptInterface::CxPrivate* pCxPrivate); - bool TemplateExists(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName); - CParamNode GetTemplate(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName); - - void RegisterScriptFunctions(const ScriptInterface& scriptInterface); -} - -#endif // INCLUDED_JSI_GUIMANAGER Property changes on: ps/trunk/source/gui/scripting/JSInterface_GUIManager.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/JSInterface_GUISize.h =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_GUISize.h (revision 23027) +++ ps/trunk/source/gui/scripting/JSInterface_GUISize.h (nonexistent) @@ -1,38 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_JSI_GUISIZE -#define INCLUDED_JSI_GUISIZE - -#include "scriptinterface/ScriptInterface.h" -#include "ps/CStr.h" - -namespace JSI_GUISize -{ - extern JSClass JSI_class; - extern JSPropertySpec JSI_props[]; - extern JSFunctionSpec JSI_methods[]; - - void RegisterScriptClass(ScriptInterface& scriptInterface); - - bool construct(JSContext* cx, uint argc, JS::Value* vp); - bool toString(JSContext* cx, uint argc, JS::Value* vp); - - CStr ToPercentString(double pix, double per); -} - -#endif // INCLUDED_JSI_GUISIZE Property changes on: ps/trunk/source/gui/scripting/JSInterface_GUISize.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp (revision 23027) +++ ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp (nonexistent) @@ -1,228 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "JSInterface_IGUIObject.h" - -#include "gui/CGUI.h" -#include "gui/CGUISetting.h" -#include "gui/IGUIObject.h" -#include "scriptinterface/ScriptExtraHeaders.h" -#include "scriptinterface/ScriptInterface.h" - -JSClass JSI_IGUIObject::JSI_class = { - "GUIObject", JSCLASS_HAS_PRIVATE, - nullptr, nullptr, - JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr -}; - -JSFunctionSpec JSI_IGUIObject::JSI_methods[] = -{ - JS_FN("toString", JSI_IGUIObject::toString, 0, 0), - JS_FN("focus", JSI_IGUIObject::focus, 0, 0), - JS_FN("blur", JSI_IGUIObject::blur, 0, 0), - JS_FN("getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0), - JS_FS_END -}; - -void JSI_IGUIObject::RegisterScriptClass(ScriptInterface& scriptInterface) -{ - scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 0, nullptr, JSI_methods, nullptr, nullptr); -} - -bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) -{ - JSAutoRequest rq(cx); - ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - - IGUIObject* e = ScriptInterface::GetPrivate(cx, obj, &JSI_IGUIObject::JSI_class); - if (!e) - return false; - - JS::RootedValue idval(cx); - if (!JS_IdToValue(cx, id, &idval)) - return false; - - std::string propName; - if (!ScriptInterface::FromJSVal(cx, idval, propName)) - return false; - - // Skip registered functions and inherited properties - // including JSInterfaces of derived classes - if (propName == "constructor" || - propName == "prototype" || - propName == "toString" || - propName == "toJSON" || - propName == "focus" || - propName == "blur" || - propName == "getTextSize" || - propName == "getComputedSize" - ) - return true; - - // Use onWhatever to access event handlers - if (propName.substr(0, 2) == "on") - { - CStr eventName(CStr(propName.substr(2)).LowerCase()); - std::map>::iterator it = e->m_ScriptHandlers.find(eventName); - if (it == e->m_ScriptHandlers.end()) - vp.setNull(); - else - vp.setObject(*it->second.get()); - return true; - } - - if (propName == "parent") - { - IGUIObject* parent = e->GetParent(); - - if (parent) - vp.set(JS::ObjectValue(*parent->GetJSObject())); - else - vp.set(JS::NullValue()); - - return true; - } - else if (propName == "children") - { - ScriptInterface::CreateArray(cx, vp); - - for (size_t i = 0; i < e->m_Children.size(); ++i) - pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]); - - return true; - } - else if (propName == "name") - { - ScriptInterface::ToJSVal(cx, vp, e->GetName()); - return true; - } - else if (e->SettingExists(propName)) - { - e->m_Settings[propName]->ToJSVal(cx, vp); - return true; - } - - JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); - return false; -} - -bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result) -{ - IGUIObject* e = ScriptInterface::GetPrivate(cx, obj, &JSI_IGUIObject::JSI_class); - if (!e) - return result.fail(JSMSG_NOT_NONNULL_OBJECT); - - JSAutoRequest rq(cx); - JS::RootedValue idval(cx); - if (!JS_IdToValue(cx, id, &idval)) - return result.fail(JSMSG_NOT_NONNULL_OBJECT); - - std::string propName; - if (!ScriptInterface::FromJSVal(cx, idval, propName)) - return result.fail(JSMSG_UNDEFINED_PROP); - - if (propName == "name") - { - std::string value; - if (!ScriptInterface::FromJSVal(cx, vp, value)) - return result.fail(JSMSG_UNDEFINED_PROP); - e->SetName(value); - return result.succeed(); - } - - JS::RootedObject vpObj(cx); - if (vp.isObject()) - vpObj = &vp.toObject(); - - // Use onWhatever to set event handlers - if (propName.substr(0, 2) == "on") - { - if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject())) - { - JS_ReportError(cx, "on- event-handlers must be functions"); - return result.fail(JSMSG_NOT_FUNCTION); - } - - CStr eventName(CStr(propName.substr(2)).LowerCase()); - e->SetScriptHandler(eventName, vpObj); - - return result.succeed(); - } - - if (e->SettingExists(propName)) - return e->m_Settings[propName]->FromJSVal(cx, vp, true) ? result.succeed() : result.fail(JSMSG_TYPE_ERR_BAD_ARGS); - - JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); - return result.fail(JSMSG_UNDEFINED_PROP); -} - -bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp) -{ - // No JSAutoRequest needed for these calls - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); - if (!e) - return false; - - ScriptInterface::ToJSVal(cx, args.rval(), "[GUIObject: " + e->GetName() + "]"); - return true; -} - -bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp) -{ - // No JSAutoRequest needed for these calls - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); - if (!e) - return false; - - e->GetGUI().SetFocusedObject(e); - args.rval().setUndefined(); - return true; -} - -bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp) -{ - // No JSAutoRequest needed for these calls - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); - if (!e) - return false; - - e->GetGUI().SetFocusedObject(nullptr); - args.rval().setUndefined(); - return true; -} - -bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp) -{ - JSAutoRequest rq(cx); - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - - IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); - if (!e) - return false; - - e->UpdateCachedSize(); - ScriptInterface::ToJSVal(cx, args.rval(), e->m_CachedActualSize); - - return true; -} Property changes on: ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/GuiScriptConversions.cpp =================================================================== --- ps/trunk/source/gui/scripting/GuiScriptConversions.cpp (revision 23027) +++ ps/trunk/source/gui/scripting/GuiScriptConversions.cpp (nonexistent) @@ -1,369 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "gui/CGUIColor.h" -#include "gui/CGUIList.h" -#include "gui/CGUISeries.h" -#include "gui/CGUISize.h" -#include "gui/IGUIObject.h" -#include "lib/external_libraries/libsdl.h" -#include "maths/Vector2D.h" -#include "ps/Hotkey.h" -#include "scriptinterface/ScriptConversions.h" - -#include - -#define SET(obj, name, value) STMT(JS::RootedValue v_(cx); AssignOrToJSVal(cx, &v_, (value)); JS_SetProperty(cx, obj, (name), v_)) - // ignore JS_SetProperty return value, because errors should be impossible - // and we can't do anything useful in the case of errors anyway - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, SDL_Event_ const& val) -{ - JSAutoRequest rq(cx); - const char* typeName; - - switch (val.ev.type) - { - case SDL_WINDOWEVENT: typeName = "windowevent"; break; - case SDL_KEYDOWN: typeName = "keydown"; break; - case SDL_KEYUP: typeName = "keyup"; break; - case SDL_MOUSEMOTION: typeName = "mousemotion"; break; - case SDL_MOUSEBUTTONDOWN: typeName = "mousebuttondown"; break; - case SDL_MOUSEBUTTONUP: typeName = "mousebuttonup"; break; - case SDL_QUIT: typeName = "quit"; break; - case SDL_HOTKEYDOWN: typeName = "hotkeydown"; break; - case SDL_HOTKEYUP: typeName = "hotkeyup"; break; - default: typeName = "(unknown)"; break; - } - - JS::RootedObject obj(cx, JS_NewPlainObject(cx)); - if (!obj) - { - ret.setUndefined(); - return; - } - - SET(obj, "type", typeName); - - switch (val.ev.type) - { - case SDL_KEYDOWN: - case SDL_KEYUP: - { - // SET(obj, "which", (int)val.ev.key.which); // (not in wsdl.h) - // SET(obj, "state", (int)val.ev.key.state); // (not in wsdl.h) - - JS::RootedObject keysym(cx, JS_NewPlainObject(cx)); - if (!keysym) - { - ret.setUndefined(); - return; - } - JS::RootedValue keysymVal(cx, JS::ObjectValue(*keysym)); - JS_SetProperty(cx, obj, "keysym", keysymVal); - - // SET(keysym, "scancode", (int)val.ev.key.keysym.scancode); // (not in wsdl.h) - SET(keysym, "sym", (int)val.ev.key.keysym.sym); - // SET(keysym, "mod", (int)val.ev.key.keysym.mod); // (not in wsdl.h) - { - SET(keysym, "unicode", JS::UndefinedHandleValue); - } - // TODO: scripts have no idea what all the key/mod enum values are; - // we should probably expose them as constants if we expect scripts to use them - - break; - } - case SDL_MOUSEMOTION: - { - // SET(obj, "which", (int)val.ev.motion.which); // (not in wsdl.h) - // SET(obj, "state", (int)val.ev.motion.state); // (not in wsdl.h) - SET(obj, "x", (int)val.ev.motion.x); - SET(obj, "y", (int)val.ev.motion.y); - // SET(obj, "xrel", (int)val.ev.motion.xrel); // (not in wsdl.h) - // SET(obj, "yrel", (int)val.ev.motion.yrel); // (not in wsdl.h) - break; - } - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - { - // SET(obj, "which", (int)val.ev.button.which); // (not in wsdl.h) - SET(obj, "button", (int)val.ev.button.button); - SET(obj, "state", (int)val.ev.button.state); - SET(obj, "x", (int)val.ev.button.x); - SET(obj, "y", (int)val.ev.button.y); - SET(obj, "clicks", (int)val.ev.button.clicks); - break; - } - case SDL_HOTKEYDOWN: - case SDL_HOTKEYUP: - { - SET(obj, "hotkey", static_cast(val.ev.user.data1)); - break; - } - } - - ret.setObject(*obj); -} - -template<> void ScriptInterface::ToJSVal(JSContext* UNUSED(cx), JS::MutableHandleValue ret, IGUIObject* const& val) -{ - if (val == nullptr) - ret.setNull(); - else - ret.setObject(*val->GetJSObject()); -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUIString& val) -{ - ScriptInterface::ToJSVal(cx, ret, val.GetOriginalString()); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUIString& out) -{ - std::wstring val; - if (!FromJSVal(cx, v, val)) - return false; - out.SetValue(val); - return true; -} - -JSVAL_VECTOR(CVector2D) -JSVAL_VECTOR(std::vector) -JSVAL_VECTOR(CGUIString) - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUIColor& val) -{ - ToJSVal(cx, ret, val); -} - -/** - * The color depends on the predefined color database stored in the current GUI page. - */ -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUIColor& out) = delete; - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CSize& val) -{ - CreateObject(cx, ret, "width", val.cx, "height", val.cy); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CSize& out) -{ - if (!v.isObject()) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "CSize value must be an object!"); - return false; - } - - if (!FromJSProperty(cx, v, "width", out.cx)) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "Failed to get CSize.cx property"); - return false; - } - - if (!FromJSProperty(cx, v, "height", out.cy)) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "Failed to get CSize.cy property"); - return false; - } - - return true; -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CPos& val) -{ - CreateObject(cx, ret, "x", val.x, "y", val.y); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CPos& out) -{ - if (!v.isObject()) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "CPos value must be an object!"); - return false; - } - - if (!FromJSProperty(cx, v, "x", out.x)) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "Failed to get CPos.x property"); - return false; - } - - if (!FromJSProperty(cx, v, "y", out.y)) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "Failed to get CPos.y property"); - return false; - } - - return true; -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CRect& val) -{ - CreateObject( - cx, - ret, - "left", val.left, - "right", val.right, - "top", val.top, - "bottom", val.bottom); -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUISize& val) -{ - val.ToJSVal(cx, ret); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUISize& out) -{ - return out.FromJSVal(cx, v); -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUIList& val) -{ - ToJSVal(cx, ret, val.m_Items); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUIList& out) -{ - return FromJSVal(cx, v, out.m_Items); -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUISeries& val) -{ - ToJSVal(cx, ret, val.m_Series); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUISeries& out) -{ - return FromJSVal(cx, v, out.m_Series); -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const EVAlign& val) -{ - std::string word; - switch (val) - { - case EVAlign_Top: - word = "top"; - break; - - case EVAlign_Bottom: - word = "bottom"; - break; - - case EVAlign_Center: - word = "center"; - break; - - default: - word = "error"; - JSAutoRequest rq(cx); - JS_ReportError(cx, "Invalid EVAlign"); - break; - } - ToJSVal(cx, ret, word); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, EVAlign& out) -{ - std::string word; - FromJSVal(cx, v, word); - - if (word == "top") - out = EVAlign_Top; - else if (word == "bottom") - out = EVAlign_Bottom; - else if (word == "center") - out = EVAlign_Center; - else - { - out = EVAlign_Top; - JSAutoRequest rq(cx); - JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')"); - return false; - } - return true; -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const EAlign& val) -{ - std::string word; - switch (val) - { - case EAlign_Left: - word = "left"; - break; - case EAlign_Right: - word = "right"; - break; - case EAlign_Center: - word = "center"; - break; - default: - word = "error"; - JSAutoRequest rq(cx); - JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')"); - break; - } - ToJSVal(cx, ret, word); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, EAlign& out) -{ - std::string word; - FromJSVal(cx, v, word); - - if (word == "left") - out = EAlign_Left; - else if (word == "right") - out = EAlign_Right; - else if (word == "center") - out = EAlign_Center; - else - { - out = EAlign_Left; - JSAutoRequest rq(cx); - JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')"); - return false; - } - return true; -} - -template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUISpriteInstance& val) -{ - ToJSVal(cx, ret, val.GetName()); -} - -template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUISpriteInstance& out) -{ - std::string name; - if (!FromJSVal(cx, v, name)) - return false; - - out.SetName(name); - return true; -} - -#undef SET Property changes on: ps/trunk/source/gui/scripting/GuiScriptConversions.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/ScriptFunctions.h =================================================================== --- ps/trunk/source/gui/scripting/ScriptFunctions.h (revision 23027) +++ ps/trunk/source/gui/scripting/ScriptFunctions.h (nonexistent) @@ -1,25 +0,0 @@ -/* Copyright (C) 2010 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_GUI_SCRIPTFUNCTIONS -#define INCLUDED_GUI_SCRIPTFUNCTIONS - -class ScriptInterface; - -void GuiScriptingInit(ScriptInterface& scriptInterface); - -#endif // INCLUDED_GUI_SCRIPTFUNCTIONS Property changes on: ps/trunk/source/gui/scripting/ScriptFunctions.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/JSInterface_IGUIObject.h =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_IGUIObject.h (revision 23027) +++ ps/trunk/source/gui/scripting/JSInterface_IGUIObject.h (nonexistent) @@ -1,39 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_JSI_IGUIOBJECT -#define INCLUDED_JSI_IGUIOBJECT - -#include "scriptinterface/ScriptInterface.h" - -namespace JSI_IGUIObject -{ - extern JSClass JSI_class; - extern JSFunctionSpec JSI_methods[]; - - void RegisterScriptClass(ScriptInterface& scriptInterface); - - bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); - bool setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result); - bool toString(JSContext* cx, uint argc, JS::Value* vp); - bool focus(JSContext* cx, uint argc, JS::Value* vp); - bool blur(JSContext* cx, uint argc, JS::Value* vp); - bool getComputedSize(JSContext* cx, uint argc, JS::Value* vp); - bool getTextSize(JSContext* cx, uint argc, JS::Value* vp); -} - -#endif // INCLUDED_JSI_IGUIOBJECT Property changes on: ps/trunk/source/gui/scripting/JSInterface_IGUIObject.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/JSInterface_GUIManager.cpp =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_GUIManager.cpp (revision 23027) +++ ps/trunk/source/gui/scripting/JSInterface_GUIManager.cpp (nonexistent) @@ -1,110 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "JSInterface_GUIManager.h" - -#include "gui/CGUI.h" -#include "gui/GUIManager.h" -#include "gui/IGUIObject.h" -#include "ps/GameSetup/Config.h" -#include "scriptinterface/ScriptInterface.h" - -// Note that the initData argument may only contain clonable data. -// Functions aren't supported for example! -void JSI_GUIManager::PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction) -{ - g_GUI->PushPage(name, pCxPrivate->pScriptInterface->WriteStructuredClone(initData), callbackFunction); -} - -void JSI_GUIManager::SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData) -{ - g_GUI->SwitchPage(name, pCxPrivate->pScriptInterface, initData); -} - -void JSI_GUIManager::PopGuiPage(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue args) -{ - if (g_GUI->GetPageCount() < 2) - { - JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); - JSAutoRequest rq(cx); - JS_ReportError(cx, "Can't pop GUI pages when less than two pages are opened!"); - return; - } - - g_GUI->PopPage(pCxPrivate->pScriptInterface->WriteStructuredClone(args)); -} - -JS::Value JSI_GUIManager::GetGUIObjectByName(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name) -{ - CGUI* guiPage = static_cast(pCxPrivate->pCBData); - - IGUIObject* guiObj = guiPage->FindObjectByName(name); - if (!guiObj) - return JS::UndefinedValue(); - - return JS::ObjectValue(*guiObj->GetJSObject()); -} - -void JSI_GUIManager::SetGlobalHotkey(ScriptInterface::CxPrivate* pCxPrivate, const std::string& hotkeyTag, JS::HandleValue function) -{ - CGUI* guiPage = static_cast(pCxPrivate->pCBData); - guiPage->SetGlobalHotkey(hotkeyTag, function); -} - -void JSI_GUIManager::UnsetGlobalHotkey(ScriptInterface::CxPrivate* pCxPrivate, const std::string& hotkeyTag) -{ - CGUI* guiPage = static_cast(pCxPrivate->pCBData); - guiPage->UnsetGlobalHotkey(hotkeyTag); -} - -std::wstring JSI_GUIManager::SetCursor(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& name) -{ - std::wstring old = g_CursorName; - g_CursorName = name; - return old; -} - -void JSI_GUIManager::ResetCursor(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) -{ - g_GUI->ResetCursor(); -} - -bool JSI_GUIManager::TemplateExists(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& templateName) -{ - return g_GUI->TemplateExists(templateName); -} - -CParamNode JSI_GUIManager::GetTemplate(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& templateName) -{ - return g_GUI->GetTemplate(templateName); -} - -void JSI_GUIManager::RegisterScriptFunctions(const ScriptInterface& scriptInterface) -{ - scriptInterface.RegisterFunction("PushGuiPage"); - scriptInterface.RegisterFunction("SwitchGuiPage"); - scriptInterface.RegisterFunction("SetGlobalHotkey"); - scriptInterface.RegisterFunction("UnsetGlobalHotkey"); - scriptInterface.RegisterFunction("PopGuiPage"); - scriptInterface.RegisterFunction("GetGUIObjectByName"); - scriptInterface.RegisterFunction("SetCursor"); - scriptInterface.RegisterFunction("ResetCursor"); - scriptInterface.RegisterFunction("TemplateExists"); - scriptInterface.RegisterFunction("GetTemplate"); -} Property changes on: ps/trunk/source/gui/scripting/JSInterface_GUIManager.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/scripting/JSInterface_GUISize.cpp =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_GUISize.cpp (revision 23027) +++ ps/trunk/source/gui/scripting/JSInterface_GUISize.cpp (nonexistent) @@ -1,125 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "JSInterface_GUISize.h" - -#include "ps/CStr.h" -#include "scriptinterface/ScriptInterface.h" - -JSClass JSI_GUISize::JSI_class = { - "GUISize", 0, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, JSI_GUISize::construct, nullptr -}; - -JSFunctionSpec JSI_GUISize::JSI_methods[] = -{ - JS_FN("toString", JSI_GUISize::toString, 0, 0), - JS_FS_END -}; - -void JSI_GUISize::RegisterScriptClass(ScriptInterface& scriptInterface) -{ - scriptInterface.DefineCustomObjectType(&JSI_GUISize::JSI_class, JSI_GUISize::construct, 0, nullptr, JSI_GUISize::JSI_methods, nullptr, nullptr); -} - -bool JSI_GUISize::construct(JSContext* cx, uint argc, JS::Value* vp) -{ - JSAutoRequest rq(cx); - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUISize")); - - if (args.length() == 8) - { - JS_SetProperty(cx, obj, "left", args[0]); - JS_SetProperty(cx, obj, "top", args[1]); - JS_SetProperty(cx, obj, "right", args[2]); - JS_SetProperty(cx, obj, "bottom", args[3]); - JS_SetProperty(cx, obj, "rleft", args[4]); - JS_SetProperty(cx, obj, "rtop", args[5]); - JS_SetProperty(cx, obj, "rright", args[6]); - JS_SetProperty(cx, obj, "rbottom", args[7]); - } - else if (args.length() == 4) - { - JS::RootedValue zero(cx, JS::NumberValue(0)); - JS_SetProperty(cx, obj, "left", args[0]); - JS_SetProperty(cx, obj, "top", args[1]); - JS_SetProperty(cx, obj, "right", args[2]); - JS_SetProperty(cx, obj, "bottom", args[3]); - JS_SetProperty(cx, obj, "rleft", zero); - JS_SetProperty(cx, obj, "rtop", zero); - JS_SetProperty(cx, obj, "rright", zero); - JS_SetProperty(cx, obj, "rbottom", zero); - } - else - { - JS::RootedValue zero(cx, JS::NumberValue(0)); - JS_SetProperty(cx, obj, "left", zero); - JS_SetProperty(cx, obj, "top", zero); - JS_SetProperty(cx, obj, "right", zero); - JS_SetProperty(cx, obj, "bottom", zero); - JS_SetProperty(cx, obj, "rleft", zero); - JS_SetProperty(cx, obj, "rtop", zero); - JS_SetProperty(cx, obj, "rright", zero); - JS_SetProperty(cx, obj, "rbottom", zero); - } - - args.rval().setObject(*obj); - return true; -} - -// Produces "10", "-10", "50%", "50%-10", "50%+10", etc -CStr JSI_GUISize::ToPercentString(double pix, double per) -{ - if (per == 0) - return CStr::FromDouble(pix); - - return CStr::FromDouble(per)+"%"+(pix == 0.0 ? CStr() : pix > 0.0 ? CStr("+")+CStr::FromDouble(pix) : CStr::FromDouble(pix)); -} - -bool JSI_GUISize::toString(JSContext* cx, uint argc, JS::Value* vp) -{ - // JSAutoRequest not needed for the calls below - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - CStr buffer; - - ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - double val, valr; - -#define SIDE(side) \ - pScriptInterface->GetProperty(args.thisv(), #side, val); \ - pScriptInterface->GetProperty(args.thisv(), "r"#side, valr); \ - buffer += ToPercentString(val, valr); - - SIDE(left); - buffer += " "; - SIDE(top); - buffer += " "; - SIDE(right); - buffer += " "; - SIDE(bottom); -#undef SIDE - - ScriptInterface::ToJSVal(cx, args.rval(), buffer); - return true; -} Property changes on: ps/trunk/source/gui/scripting/JSInterface_GUISize.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CSlider.h =================================================================== --- ps/trunk/source/gui/CSlider.h (revision 23027) +++ ps/trunk/source/gui/CSlider.h (nonexistent) @@ -1,69 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CSLIDER -#define INCLUDED_CSLIDER - -#include "gui/IGUIObject.h" -#include "gui/CGUISprite.h" - -class CSlider : public IGUIObject -{ - GUI_OBJECT(CSlider) - -public: - CSlider(CGUI& pGUI); - virtual ~CSlider(); - -protected: - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - virtual void Draw(); - - /** - * Change settings and send the script event - */ - void UpdateValue(); - - CRect GetButtonRect() const; - - /** - * @return ratio between the value of the slider and its actual size in the GUI - */ - float GetSliderRatio() const; - - void IncrementallyChangeValue(const float value); - - // Settings - float m_ButtonSide; - i32 m_CellID; - float m_MinValue; - float m_MaxValue; - CGUISpriteInstance m_Sprite; - CGUISpriteInstance m_SpriteBar; - float m_Value; - -private: - bool m_IsPressed; - CPos m_Mouse; -}; - -#endif // INCLUDED_CSLIDER Property changes on: ps/trunk/source/gui/CSlider.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUIList.h =================================================================== --- ps/trunk/source/gui/CGUIList.h (revision 23027) +++ ps/trunk/source/gui/CGUIList.h (nonexistent) @@ -1,43 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CGUILIST -#define INCLUDED_CGUILIST - -#include "gui/CGUIString.h" - -#include - -class CGUIList -{ -public: // struct:ish (but for consistency I call it _C_GUIList, and - // for the same reason it is a class, so that confusion doesn't - // appear when forward declaring. - - // Avoid copying the vector. - NONCOPYABLE(CGUIList); - MOVABLE(CGUIList); - CGUIList() = default; - - /** - * List of items (as text), the post-processed result is stored in - * the IGUITextOwner structure of this class. - */ - std::vector m_Items; -}; - -#endif Property changes on: ps/trunk/source/gui/CGUIList.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CText.cpp =================================================================== --- ps/trunk/source/gui/CText.cpp (revision 23027) +++ ps/trunk/source/gui/CText.cpp (nonexistent) @@ -1,284 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CText.h" - -#include "gui/CGUI.h" -#include "gui/CGUIScrollBarVertical.h" -#include "gui/CGUIText.h" -#include "scriptinterface/ScriptInterface.h" - -CText::CText(CGUI& pGUI) - : IGUIObject(pGUI), - IGUIScrollBarOwner(*static_cast(this)), - IGUITextOwner(*static_cast(this)), - m_BufferZone(), - m_Caption(), - m_CellID(), - m_Clip(), - m_Font(), - m_ScrollBar(), - m_ScrollBarStyle(), - m_ScrollBottom(), - m_ScrollTop(), - m_Sprite(), - m_TextAlign(), - m_TextVAlign(), - m_TextColor(), - m_TextColorDisabled(), - m_IconTooltip(), - m_IconTooltipStyle() -{ - RegisterSetting("buffer_zone", m_BufferZone); - RegisterSetting("caption", m_Caption); - RegisterSetting("cell_id", m_CellID); - RegisterSetting("clip", m_Clip); - RegisterSetting("font", m_Font); - RegisterSetting("scrollbar", m_ScrollBar); - RegisterSetting("scrollbar_style", m_ScrollBarStyle); - RegisterSetting("scroll_bottom", m_ScrollBottom); - RegisterSetting("scroll_top", m_ScrollTop); - RegisterSetting("sprite", m_Sprite); - RegisterSetting("text_align", m_TextAlign); - RegisterSetting("text_valign", m_TextVAlign); - RegisterSetting("textcolor", m_TextColor); - RegisterSetting("textcolor_disabled", m_TextColorDisabled); - // Private settings - RegisterSetting("_icon_tooltip", m_IconTooltip); - RegisterSetting("_icon_tooltip_style", m_IconTooltipStyle); - - //SetSetting("ghost", true, true); - SetSetting("scrollbar", false, true); - SetSetting("clip", true, true); - - // Add scroll-bar - CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI); - bar->SetRightAligned(true); - AddScrollBar(bar); - - // Add text - AddText(); -} - -CText::~CText() -{ -} - -void CText::SetupText() -{ - if (m_GeneratedTexts.empty()) - return; - - float width = m_CachedActualSize.GetWidth(); - // remove scrollbar if applicable - if (m_ScrollBar && GetScrollBar(0).GetStyle()) - width -= GetScrollBar(0).GetStyle()->m_Width; - - m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, width, m_BufferZone, this); - - if (!m_ScrollBar) - CalculateTextPosition(m_CachedActualSize, m_TextPos, m_GeneratedTexts[0]); - - // Setup scrollbar - if (m_ScrollBar) - { - // If we are currently scrolled to the bottom of the text, - // then add more lines of text, update the scrollbar so we - // stick to the bottom. - // (Use 1.5px delta so this triggers the first time caption is set) - bool bottom = false; - if (m_ScrollBottom && GetScrollBar(0).GetPos() > GetScrollBar(0).GetMaxPos() - 1.5f) - bottom = true; - - GetScrollBar(0).SetScrollRange(m_GeneratedTexts[0].GetSize().cy); - GetScrollBar(0).SetScrollSpace(m_CachedActualSize.GetHeight()); - - 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); - - if (bottom) - GetScrollBar(0).SetPos(GetScrollBar(0).GetMaxPos()); - - if (m_ScrollTop) - GetScrollBar(0).SetPos(0.0f); - } -} - -void CText::ResetStates() -{ - IGUIObject::ResetStates(); - IGUIScrollBarOwner::ResetStates(); -} - -void CText::UpdateCachedSize() -{ - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); -} - -void CText::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - IGUIScrollBarOwner::HandleMessage(Message); - //IGUITextOwner::HandleMessage(Message); <== placed it after the switch instead! - - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - if (Message.value == "scrollbar") - SetupText(); - - // Update scrollbar - if (Message.value == "scrollbar_style") - { - GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); - SetupText(); - } - - 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 - SGUIMessage msg(GUIM_MOUSE_MOTION); - HandleMessage(msg); - 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 - SGUIMessage msg(GUIM_MOUSE_MOTION); - HandleMessage(msg); - break; - } - case GUIM_LOAD: - { - 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); - GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); - break; - } - - default: - break; - } - - IGUITextOwner::HandleMessage(Message); -} - -void CText::Draw() -{ - float bz = GetBufferedZ(); - - if (m_ScrollBar) - IGUIScrollBarOwner::Draw(); - - m_pGUI.DrawSprite(m_Sprite, m_CellID, bz, m_CachedActualSize); - - float scroll = 0.f; - if (m_ScrollBar) - scroll = GetScrollBar(0).GetPos(); - - // Clipping area (we'll have to subtract the scrollbar) - CRect cliparea; - if (m_Clip) - { - cliparea = m_CachedActualSize; - - if (m_ScrollBar) - { - // subtract scrollbar from cliparea - if (cliparea.right > GetScrollBar(0).GetOuterRect().left && - cliparea.right <= GetScrollBar(0).GetOuterRect().right) - cliparea.right = GetScrollBar(0).GetOuterRect().left; - - if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && - cliparea.left < GetScrollBar(0).GetOuterRect().right) - cliparea.left = GetScrollBar(0).GetOuterRect().right; - } - } - - const CGUIColor& color = m_Enabled ? m_TextColor : m_TextColorDisabled; - - if (m_ScrollBar) - DrawText(0, color, m_CachedActualSize.TopLeft() - CPos(0.f, scroll), bz + 0.1f, cliparea); - else - DrawText(0, color, m_TextPos, bz + 0.1f, cliparea); -} - -bool CText::MouseOverIcon() -{ - for (const CGUIText& guitext : m_GeneratedTexts) - for (const CGUIText::SSpriteCall& spritecall : guitext.GetSpriteCalls()) - { - // Check mouse over sprite - if (!spritecall.m_Area.PointInside(m_pGUI.GetMousePos() - m_CachedActualSize.TopLeft())) - continue; - - // If tooltip exists, set the property - if (!spritecall.m_Tooltip.empty()) - { - SetSettingFromString("_icon_tooltip_style", spritecall.m_TooltipStyle, true); - SetSettingFromString("_icon_tooltip", spritecall.m_Tooltip, true); - } - - return true; - } - - return false; -} - -void CText::RegisterScriptFunctions() -{ - JSContext* cx = m_pGUI.GetScriptInterface()->GetContext(); - JSAutoRequest rq(cx); - JS_DefineFunctions(cx, m_JSObject, CText::JSI_methods); -} - -JSFunctionSpec CText::JSI_methods[] = -{ - JS_FN("getTextSize", CText::GetTextSize, 0, 0), - JS_FS_END -}; - -bool CText::GetTextSize(JSContext* cx, uint argc, JS::Value* vp) -{ - // No JSAutoRequest needed for these calls - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - CText* thisObj = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); - if (!thisObj) - { - JSAutoRequest rq(cx); - JS_ReportError(cx, "This is not a CText object!"); - return false; - } - - thisObj->UpdateText(); - - ScriptInterface::ToJSVal(cx, args.rval(), thisObj->m_GeneratedTexts[0].GetSize()); - return true; -} Property changes on: ps/trunk/source/gui/CText.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUIScrollBarOwner.cpp =================================================================== --- ps/trunk/source/gui/IGUIScrollBarOwner.cpp (revision 23027) +++ ps/trunk/source/gui/IGUIScrollBarOwner.cpp (nonexistent) @@ -1,68 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "IGUIScrollBarOwner.h" - -#include "gui/CGUI.h" -#include "gui/IGUIScrollBar.h" - -IGUIScrollBarOwner::IGUIScrollBarOwner(IGUIObject& pObject) - : m_pObject(pObject) -{ -} - -IGUIScrollBarOwner::~IGUIScrollBarOwner() -{ - for (IGUIScrollBar* const& sb : m_ScrollBars) - delete sb; -} - -void IGUIScrollBarOwner::ResetStates() -{ - for (IGUIScrollBar* const& sb : m_ScrollBars) - sb->SetBarPressed(false); -} - -void IGUIScrollBarOwner::AddScrollBar(IGUIScrollBar* scrollbar) -{ - scrollbar->SetHostObject(this); - m_ScrollBars.push_back(scrollbar); -} - -const SGUIScrollBarStyle* IGUIScrollBarOwner::GetScrollBarStyle(const CStr& style) const -{ - return m_pObject.GetGUI().GetScrollBarStyle(style); -} - -void IGUIScrollBarOwner::HandleMessage(SGUIMessage& msg) -{ - for (IGUIScrollBar* const& sb : m_ScrollBars) - sb->HandleMessage(msg); -} - -void IGUIScrollBarOwner::Draw() -{ - for (IGUIScrollBar* const& sb : m_ScrollBars) - sb->Draw(); -} - -float IGUIScrollBarOwner::GetScrollBarPos(const int index) const -{ - return m_ScrollBars[index]->GetPos(); -} Property changes on: ps/trunk/source/gui/IGUIScrollBarOwner.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CSlider.cpp =================================================================== --- ps/trunk/source/gui/CSlider.cpp (revision 23027) +++ ps/trunk/source/gui/CSlider.cpp (nonexistent) @@ -1,139 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CSlider.h" - -#include "gui/CGUI.h" -#include "maths/MathUtil.h" - -CSlider::CSlider(CGUI& pGUI) - : IGUIObject(pGUI), - m_IsPressed(), - m_ButtonSide(), - m_CellID(), - m_MaxValue(), - m_MinValue(), - m_Sprite(), - m_SpriteBar(), - m_Value() -{ - RegisterSetting("button_width", m_ButtonSide); - RegisterSetting("cell_id", m_CellID); - RegisterSetting("max_value", m_MaxValue); - RegisterSetting("min_value", m_MinValue); - RegisterSetting("sprite", m_Sprite); - RegisterSetting("sprite_bar", m_SpriteBar); - RegisterSetting("value", m_Value); - - m_Value = Clamp(m_Value, m_MinValue, m_MaxValue); -} - -CSlider::~CSlider() -{ -} - -float CSlider::GetSliderRatio() const -{ - return (m_MaxValue - m_MinValue) / (m_CachedActualSize.GetWidth() - m_ButtonSide); -} - -void CSlider::IncrementallyChangeValue(const float difference) -{ - m_Value = Clamp(m_Value + difference, m_MinValue, m_MaxValue); - UpdateValue(); -} - -void CSlider::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - { - m_Value = Clamp(m_Value, m_MinValue, m_MaxValue); - break; - } - case GUIM_MOUSE_WHEEL_DOWN: - { - if (m_IsPressed) - break; - IncrementallyChangeValue(-0.01f); - break; - } - case GUIM_MOUSE_WHEEL_UP: - { - if (m_IsPressed) - break; - IncrementallyChangeValue(0.01f); - break; - } - case GUIM_MOUSE_PRESS_LEFT: - { - m_Mouse = m_pGUI.GetMousePos(); - m_IsPressed = true; - - IncrementallyChangeValue((m_Mouse.x - GetButtonRect().CenterPoint().x) * GetSliderRatio()); - break; - } - case GUIM_MOUSE_RELEASE_LEFT: - { - m_IsPressed = false; - break; - } - case GUIM_MOUSE_MOTION: - { - if (!IsMouseOver()) - m_IsPressed = false; - if (m_IsPressed) - { - float difference = float(m_pGUI.GetMousePos().x - m_Mouse.x) * GetSliderRatio(); - m_Mouse = m_pGUI.GetMousePos(); - IncrementallyChangeValue(difference); - } - break; - } - default: - break; - } -} - -void CSlider::Draw() -{ - CRect slider_line(m_CachedActualSize); - slider_line.left += m_ButtonSide / 2.0f; - slider_line.right -= m_ButtonSide / 2.0f; - float bz = GetBufferedZ(); - m_pGUI.DrawSprite(m_SpriteBar, m_CellID, bz, slider_line); - m_pGUI.DrawSprite(m_Sprite, m_CellID, bz, GetButtonRect()); -} - -void CSlider::UpdateValue() -{ - SetSetting("value", m_Value, true); - ScriptEvent("valuechange"); -} - -CRect CSlider::GetButtonRect() const -{ - float ratio = m_MaxValue > m_MinValue ? (m_Value - m_MinValue) / (m_MaxValue - m_MinValue) : 0.0f; - float x = m_CachedActualSize.left + ratio * (m_CachedActualSize.GetWidth() - m_ButtonSide); - float y = m_CachedActualSize.top + (m_CachedActualSize.GetHeight() - m_ButtonSide) / 2.0; - return CRect(x, y, x + m_ButtonSide, y + m_ButtonSide); -} Property changes on: ps/trunk/source/gui/CSlider.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUIString.cpp =================================================================== --- ps/trunk/source/gui/CGUIString.cpp (revision 23027) +++ ps/trunk/source/gui/CGUIString.cpp (nonexistent) @@ -1,474 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CGUIString.h" - -#include "graphics/FontMetrics.h" -#include "gui/CGUI.h" -#include "lib/utf8.h" -#include "ps/CLogger.h" - -#include -#include - -// List of word delimiter bounds -// The list contains ranges of word delimiters. The odd indexed chars are the start -// of a range, the even are the end of a range. The list must be sorted in INCREASING ORDER -static const int NUM_WORD_DELIMITERS = 4*2; -static const u16 WordDelimiters[NUM_WORD_DELIMITERS] = { - ' ' , ' ', // spaces - '-' , '-', // hyphens - 0x3000, 0x31FF, // ideographic symbols - 0x3400, 0x9FFF -// TODO add unicode blocks of other languages that don't use spaces -}; - -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(const CGUI& pGUI, SFeedback& Feedback, CStrIntern DefaultFont, const int& from, const int& to, const bool FirstLine, const IGUIObject* pObject) const -{ - // Reset width and height, because they will be determined with incrementation - // or comparisons. - Feedback.Reset(); - - // Check out which text chunk this is within. - for (const TextChunk& textChunk : m_TextChunks) - { - // Get the area that is overlapped by both the TextChunk and - // by the from/to inputted. - int _from = std::max(from, textChunk.m_From); - int _to = std::min(to, textChunk.m_To); - - // If from is larger than to, then they are not overlapping - if (_to == _from && textChunk.m_From == textChunk.m_To) - { - // These should never be able to have more than one tag. - ENSURE(textChunk.m_Tags.size() == 1); - - // Icons and images are placed on exactly one position - // in the words-list, and they can be counted twice if placed - // on an edge. But there is always only one logical preference - // that we want. This check filters the unwanted. - - // it's in the end of one word, and the icon - // should really belong to the beginning of the next one - if (_to == to && to >= 1 && to < (int)m_RawString.length()) - { - if (m_RawString[to-1] == ' ' || - m_RawString[to-1] == '-' || - m_RawString[to-1] == '\n') - continue; - } - // This std::string is just a break - if (_from == from && from >= 1) - { - if (m_RawString[from] == '\n' && - m_RawString[from-1] != '\n' && - m_RawString[from-1] != ' ' && - m_RawString[from-1] != '-') - continue; - } - - const TextChunk::Tag& tag = textChunk.m_Tags[0]; - ENSURE(tag.m_TagType == TextChunk::Tag::TAG_IMGLEFT || - tag.m_TagType == TextChunk::Tag::TAG_IMGRIGHT || - tag.m_TagType == TextChunk::Tag::TAG_ICON); - - const std::string& path = utf8_from_wstring(tag.m_TagValue); - if (!pGUI.HasIcon(path)) - { - if (pObject) - LOGERROR("Trying to use an icon, imgleft or imgright-tag with an undefined icon (\"%s\").", path.c_str()); - continue; - } - - switch (tag.m_TagType) - { - case TextChunk::Tag::TAG_IMGLEFT: - Feedback.m_Images[SFeedback::Left].push_back(path); - break; - case TextChunk::Tag::TAG_IMGRIGHT: - Feedback.m_Images[SFeedback::Right].push_back(path); - break; - case TextChunk::Tag::TAG_ICON: - { - // 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 virtually for nothing more. - CGUIText::STextCall TextCall; - - // Also add it to the sprites being rendered. - CGUIText::SSpriteCall SpriteCall; - - // Get Icon from icon database in pGUI - const SGUIIcon& icon = pGUI.GetIcon(path); - - const CSize& size = icon.m_Size; - - // append width, and make maximum height the height. - Feedback.m_Size.cx += size.cx; - Feedback.m_Size.cy = std::max(Feedback.m_Size.cy, size.cy); - - // These are also needed later - TextCall.m_Size = size; - SpriteCall.m_Area = size; - - // Handle additional attributes - for (const TextChunk::Tag::TagAttribute& tagAttrib : tag.m_TagAttributes) - { - if (tagAttrib.attrib == L"displace" && !tagAttrib.value.empty()) - { - // Displace the sprite - CSize displacement; - // Parse the value - if (!CGUI::ParseString(&pGUI, tagAttrib.value, displacement)) - LOGERROR("Error parsing 'displace' value for tag [ICON]"); - else - SpriteCall.m_Area += displacement; - } - else if (tagAttrib.attrib == L"tooltip") - SpriteCall.m_Tooltip = tagAttrib.value; - else if (tagAttrib.attrib == L"tooltip_style") - SpriteCall.m_TooltipStyle = tagAttrib.value; - } - - SpriteCall.m_Sprite = icon.m_SpriteName; - SpriteCall.m_CellID = icon.m_CellID; - - // Add sprite call - Feedback.m_SpriteCalls.push_back(std::move(SpriteCall)); - - // Finalize text call - TextCall.m_pSpriteCall = &Feedback.m_SpriteCalls.back(); - - // Add text call - Feedback.m_TextCalls.emplace_back(std::move(TextCall)); - - break; - } - NODEFAULT; - } - } - else if (_to > _from && !Feedback.m_NewLine) - { - CGUIText::STextCall TextCall; - - // Set defaults - TextCall.m_Font = DefaultFont; - TextCall.m_UseCustomColor = false; - - TextCall.m_String = m_RawString.substr(_from, _to-_from); - - // Go through tags and apply changes. - for (const TextChunk::Tag& tag : textChunk.m_Tags) - { - switch (tag.m_TagType) - { - case TextChunk::Tag::TAG_COLOR: - TextCall.m_UseCustomColor = true; - - if (!CGUI::ParseString(&pGUI, tag.m_TagValue, TextCall.m_Color) && pObject) - LOGERROR("Error parsing the value of a [color]-tag in GUI text when reading object \"%s\".", pObject->GetPresentableName().c_str()); - break; - case TextChunk::Tag::TAG_FONT: - // TODO Gee: (2004-08-15) Check if Font exists? - TextCall.m_Font = CStrIntern(utf8_from_wstring(tag.m_TagValue)); - break; - default: - LOGERROR("Encountered unexpected tag applied to text"); - break; - } - } - - // Calculate the size of the font - CSize size; - int cx, cy; - CFontMetrics font (TextCall.m_Font); - font.CalculateStringSize(TextCall.m_String.c_str(), cx, cy); - // For anything other than the first line, the line spacing - // needs to be considered rather than just the height of the text - if (!FirstLine) - cy = font.GetLineSpacing(); - - size.cx = (float)cx; - size.cy = (float)cy; - - // Append width, and make maximum height the height. - Feedback.m_Size.cx += size.cx; - Feedback.m_Size.cy = std::max(Feedback.m_Size.cy, size.cy); - - // These are also needed later - TextCall.m_Size = size; - - if (!TextCall.m_String.empty() && TextCall.m_String[0] == '\n') - Feedback.m_NewLine = true; - - // Add text-chunk - Feedback.m_TextCalls.emplace_back(std::move(TextCall)); - } - } -} - -bool CGUIString::TextChunk::Tag::SetTagType(const CStrW& tagtype) -{ - TagType t = GetTagType(tagtype); - if (t == TAG_INVALID) - return false; - - m_TagType = t; - return true; -} - -CGUIString::TextChunk::Tag::TagType CGUIString::TextChunk::Tag::GetTagType(const CStrW& tagtype) const -{ - if (tagtype == L"color") - return TAG_COLOR; - if (tagtype == L"font") - return TAG_FONT; - if (tagtype == L"icon") - return TAG_ICON; - if (tagtype == L"imgleft") - return TAG_IMGLEFT; - if (tagtype == L"imgright") - return TAG_IMGRIGHT; - - return TAG_INVALID; -} - -void CGUIString::SetValue(const CStrW& str) -{ - m_OriginalString = str; - - m_TextChunks.clear(); - m_Words.clear(); - m_RawString.clear(); - - // Current Text Chunk - CGUIString::TextChunk CurrentTextChunk; - CurrentTextChunk.m_From = 0; - - int l = str.length(); - int rawpos = 0; - CStrW tag; - std::vector tags; - bool closing = false; - for (int p = 0; p < l; ++p) - { - TextChunk::Tag tag_; - switch (str[p]) - { - case L'[': - CurrentTextChunk.m_To = rawpos; - // Add the current chunks if it is not empty - if (CurrentTextChunk.m_From != rawpos) - m_TextChunks.push_back(CurrentTextChunk); - CurrentTextChunk.m_From = rawpos; - - closing = false; - if (++p == l) - { - LOGERROR("Partial tag at end of string '%s'", utf8_from_wstring(str)); - break; - } - if (str[p] == L'/') - { - closing = true; - if (tags.empty()) - { - LOGERROR("Encountered closing tag without having any open tags. At %d in '%s'", p, utf8_from_wstring(str)); - break; - } - if (++p == l) - { - LOGERROR("Partial closing tag at end of string '%s'", utf8_from_wstring(str)); - break; - } - } - tag.clear(); - // Parse tag - for (; p < l && str[p] != L']'; ++p) - { - CStrW name, param; - switch (str[p]) - { - case L' ': - if (closing) // We still parse them to make error handling cleaner - LOGERROR("Closing tags do not support parameters (at pos %d '%s')", p, utf8_from_wstring(str)); - - // parse something="something else" - for (++p; p < l && str[p] != L'='; ++p) - name.push_back(str[p]); - - if (p == l) - { - LOGERROR("Parameter without value at pos %d '%s'", p, utf8_from_wstring(str)); - break; - } - FALLTHROUGH; - case L'=': - // parse a quoted parameter - if (closing) // We still parse them to make error handling cleaner - LOGERROR("Closing tags do not support parameters (at pos %d '%s')", p, utf8_from_wstring(str)); - - if (++p == l) - { - LOGERROR("Expected parameter, got end of string '%s'", utf8_from_wstring(str)); - break; - } - if (str[p] != L'"') - { - LOGERROR("Unquoted parameters are not supported (at pos %d '%s')", p, utf8_from_wstring(str)); - break; - } - for (++p; p < l && str[p] != L'"'; ++p) - { - switch (str[p]) - { - case L'\\': - if (++p == l) - { - LOGERROR("Escape character at end of string '%s'", utf8_from_wstring(str)); - break; - } - // NOTE: We do not support \n in tag parameters - FALLTHROUGH; - default: - param.push_back(str[p]); - } - } - - if (!name.empty()) - { - TextChunk::Tag::TagAttribute a = {name, param}; - tag_.m_TagAttributes.push_back(a); - } - else - tag_.m_TagValue = param; - break; - default: - tag.push_back(str[p]); - break; - } - } - - if (!tag_.SetTagType(tag)) - { - LOGERROR("Invalid tag '%s' at %d in '%s'", utf8_from_wstring(tag), p, utf8_from_wstring(str)); - break; - } - if (!closing) - { - if (tag_.m_TagType == TextChunk::Tag::TAG_IMGRIGHT - || tag_.m_TagType == TextChunk::Tag::TAG_IMGLEFT - || tag_.m_TagType == TextChunk::Tag::TAG_ICON) - { - TextChunk FreshTextChunk = { rawpos, rawpos }; - FreshTextChunk.m_Tags.push_back(tag_); - m_TextChunks.push_back(FreshTextChunk); - } - else - { - tags.push_back(tag); - CurrentTextChunk.m_Tags.push_back(tag_); - } - } - else - { - if (tag != tags.back()) - { - LOGERROR("Closing tag '%s' does not match last opened tag '%s' at %d in '%s'", utf8_from_wstring(tag), utf8_from_wstring(tags.back()), p, utf8_from_wstring(str)); - break; - } - - tags.pop_back(); - CurrentTextChunk.m_Tags.pop_back(); - } - break; - case L'\\': - if (++p == l) - { - LOGERROR("Escape character at end of string '%s'", utf8_from_wstring(str)); - break; - } - if (str[p] == L'n') - { - ++rawpos; - m_RawString.push_back(L'\n'); - break; - } - FALLTHROUGH; - default: - ++rawpos; - m_RawString.push_back(str[p]); - break; - } - } - - // Add the chunk after the last tag - if (CurrentTextChunk.m_From != rawpos) - { - CurrentTextChunk.m_To = rawpos; - m_TextChunks.push_back(CurrentTextChunk); - } - - - // Add a delimiter at start and at end, it helps when - // processing later, because we don't have make exceptions for - // those cases. - m_Words.push_back(0); - - // Add word boundaries in increasing order - for (u32 i = 0; i < m_RawString.length(); ++i) - { - wchar_t c = m_RawString[i]; - if (c == '\n') - { - m_Words.push_back((int)i); - m_Words.push_back((int)i+1); - continue; - } - for (int n = 0; n < NUM_WORD_DELIMITERS; n += 2) - { - if (c <= WordDelimiters[n+1]) - { - if (c >= WordDelimiters[n]) - m_Words.push_back((int)i+1); - // assume the WordDelimiters list is stored in increasing order - break; - } - } - } - - m_Words.push_back((int)m_RawString.length()); - - // Remove duplicates (only if larger than 2) - if (m_Words.size() <= 2) - return; - - m_Words.erase(std::unique(m_Words.begin(), m_Words.end()), m_Words.end()); -} Property changes on: ps/trunk/source/gui/CGUIString.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CChart.cpp =================================================================== --- ps/trunk/source/gui/CChart.cpp (revision 23027) +++ ps/trunk/source/gui/CChart.cpp (nonexistent) @@ -1,318 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CChart.h" - -#include "graphics/ShaderManager.h" -#include "gui/CGUIList.h" -#include "gui/CGUISeries.h" -#include "gui/CGUIString.h" -#include "gui/GUIMatrix.h" -#include "ps/CLogger.h" -#include "ps/Profile.h" -#include "renderer/Renderer.h" - -#include - -CChart::CChart(CGUI& pGUI) - : IGUIObject(pGUI), - IGUITextOwner(*static_cast(this)), - m_AxisColor(), - m_AxisWidth(), - m_BufferZone(), - m_Font(), - m_FormatX(), - m_FormatY(), - m_SeriesColor(), - m_SeriesSetting(), - m_TextAlign() -{ - RegisterSetting("axis_color", m_AxisColor); - RegisterSetting("axis_width", m_AxisWidth); - RegisterSetting("buffer_zone", m_BufferZone); - RegisterSetting("font", m_Font); - RegisterSetting("format_x", m_FormatX); - RegisterSetting("format_y", m_FormatY); - RegisterSetting("series_color", m_SeriesColor); - RegisterSetting("series", m_SeriesSetting); - RegisterSetting("text_align", m_TextAlign); -} - -CChart::~CChart() -{ -} - -void CChart::UpdateCachedSize() -{ - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); -} - -void CChart::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - // IGUITextOwner::HandleMessage(Message); performed in UpdateSeries - - // TODO: implement zoom - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - { - UpdateSeries(); - break; - } - } -} - -void CChart::DrawLine(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const -{ - shader->Uniform(str_color, color); - shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); - shader->AssertPointersBound(); - - glEnable(GL_LINE_SMOOTH); - glLineWidth(1.1f); - if (!g_Renderer.m_SkipSubmit) - glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); - glLineWidth(1.0f); - glDisable(GL_LINE_SMOOTH); -} - -void CChart::DrawTriangleStrip(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const -{ - shader->Uniform(str_color, color); - shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); - shader->AssertPointersBound(); - - if (!g_Renderer.m_SkipSubmit) - glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size() / 3); -} - -void CChart::DrawAxes(const CShaderProgramPtr& shader) const -{ - const float bz = GetBufferedZ(); - CRect rect = GetChartRect(); - std::vector vertices; - vertices.reserve(30); -#define ADD(x, y) vertices.push_back(x); vertices.push_back(y); vertices.push_back(bz + 0.5f); - ADD(m_CachedActualSize.right, m_CachedActualSize.bottom); - ADD(rect.right + m_AxisWidth, rect.bottom); - ADD(m_CachedActualSize.left, m_CachedActualSize.bottom); - ADD(rect.left, rect.bottom); - ADD(m_CachedActualSize.left, m_CachedActualSize.top); - ADD(rect.left, rect.top - m_AxisWidth); -#undef ADD - DrawTriangleStrip(shader, m_AxisColor, vertices); -} - -void CChart::Draw() -{ - PROFILE3("render chart"); - - if (m_Series.empty()) - return; - - const float bz = GetBufferedZ(); - CRect rect = GetChartRect(); - const float width = rect.GetWidth(); - const float height = rect.GetHeight(); - - // Disable depth updates to prevent apparent z-fighting-related issues - // with some drivers causing units to get drawn behind the texture. - glDepthMask(0); - - // Setup the render state - CMatrix3D transform = GetDefaultGuiMatrix(); - CShaderDefines lineDefines; - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines); - tech->BeginPass(); - CShaderProgramPtr shader = tech->GetShader(); - shader->Uniform(str_transform, transform); - - CVector2D scale(width / (m_RightTop.X - m_LeftBottom.X), height / (m_RightTop.Y - m_LeftBottom.Y)); - for (const CChartData& data : m_Series) - { - if (data.m_Points.empty()) - continue; - - std::vector vertices; - for (const CVector2D& point : data.m_Points) - { - if (fabs(point.X) != std::numeric_limits::infinity() && fabs(point.Y) != std::numeric_limits::infinity()) - { - vertices.push_back(rect.left + (point.X - m_LeftBottom.X) * scale.X); - vertices.push_back(rect.bottom - (point.Y - m_LeftBottom.Y) * scale.Y); - vertices.push_back(bz + 0.5f); - } - else - { - DrawLine(shader, data.m_Color, vertices); - vertices.clear(); - } - } - if (!vertices.empty()) - DrawLine(shader, data.m_Color, vertices); - } - - if (m_AxisWidth > 0) - DrawAxes(shader); - - tech->EndPass(); - - // Reset depth mask - glDepthMask(1); - - for (size_t i = 0; i < m_TextPositions.size(); ++i) - DrawText(i, CGUIColor(1.f, 1.f, 1.f, 1.f), m_TextPositions[i], bz + 0.5f); -} - -CRect CChart::GetChartRect() const -{ - return CRect( - m_CachedActualSize.TopLeft() + CPos(m_AxisWidth, m_AxisWidth), - m_CachedActualSize.BottomRight() - CPos(m_AxisWidth, m_AxisWidth) - ); -} - -void CChart::UpdateSeries() -{ - m_Series.clear(); - m_Series.resize(m_SeriesSetting.m_Series.size()); - - for (size_t i = 0; i < m_SeriesSetting.m_Series.size(); ++i) - { - CChartData& data = m_Series[i]; - - if (i < m_SeriesColor.m_Items.size() && !data.m_Color.ParseString(m_pGUI, m_SeriesColor.m_Items[i].GetOriginalString().ToUTF8(), 0)) - LOGWARNING("GUI: Error parsing 'series_color' (\"%s\")", utf8_from_wstring(m_SeriesColor.m_Items[i].GetOriginalString())); - - data.m_Points = m_SeriesSetting.m_Series[i]; - } - UpdateBounds(); - - SetupText(); -} - -void CChart::SetupText() -{ - m_GeneratedTexts.clear(); - m_TextPositions.clear(); - - if (m_Series.empty()) - return; - - // Add Y-axis - const float height = GetChartRect().GetHeight(); - // TODO: split values depend on the format; - if (m_EqualY) - { - // We don't need to generate many items for equal values - AddFormattedValue(m_FormatY, m_RightTop.Y, m_Font, m_BufferZone); - m_TextPositions.emplace_back(GetChartRect().TopLeft()); - } - else - for (int i = 0; i < 3; ++i) - { - AddFormattedValue(m_FormatY, m_RightTop.Y - (m_RightTop.Y - m_LeftBottom.Y) / 3.f * i, m_Font, m_BufferZone); - m_TextPositions.emplace_back(GetChartRect().TopLeft() + CPos(0.f, height / 3.f * i)); - } - - // Add X-axis - const float width = GetChartRect().GetWidth(); - if (m_EqualX) - { - CSize text_size = AddFormattedValue(m_FormatX, m_RightTop.X, m_Font, m_BufferZone); - m_TextPositions.emplace_back(GetChartRect().BottomRight() - text_size); - } - else - for (int i = 0; i < 3; ++i) - { - CSize text_size = AddFormattedValue(m_FormatX, m_RightTop.X - (m_RightTop.X - m_LeftBottom.X) / 3 * i, m_Font, m_BufferZone); - m_TextPositions.emplace_back(GetChartRect().BottomRight() - text_size - CPos(width / 3 * i, 0.f)); - } -} - -CSize CChart::AddFormattedValue(const CStrW& format, const float value, const CStrW& font, const float buffer_zone) -{ - // TODO: we need to catch cases with equal formatted values. - CGUIString gui_str; - if (format == L"DECIMAL2") - { - wchar_t buffer[64]; - swprintf(buffer, 64, L"%.2f", value); - gui_str.SetValue(buffer); - } - else if (format == L"INTEGER") - { - wchar_t buffer[64]; - swprintf(buffer, 64, L"%d", std::lround(value)); - gui_str.SetValue(buffer); - } - else if (format == L"DURATION_SHORT") - { - const int seconds = value; - wchar_t buffer[64]; - swprintf(buffer, 64, L"%d:%02d", seconds / 60, seconds % 60); - gui_str.SetValue(buffer); - } - else if (format == L"PERCENTAGE") - { - wchar_t buffer[64]; - swprintf(buffer, 64, L"%d%%", std::lround(value)); - gui_str.SetValue(buffer); - } - else - { - LOGERROR("Unsupported chart format: " + format.EscapeToPrintableASCII()); - return CSize(); - } - - return AddText(gui_str, font, 0, buffer_zone).GetSize(); -} - -void CChart::UpdateBounds() -{ - if (m_Series.empty() || m_Series[0].m_Points.empty()) - { - m_LeftBottom = m_RightTop = CVector2D(0.f, 0.f); - return; - } - - m_LeftBottom = m_RightTop = m_Series[0].m_Points[0]; - for (const CChartData& data : m_Series) - for (const CVector2D& point : data.m_Points) - { - if (fabs(point.X) != std::numeric_limits::infinity() && point.X < m_LeftBottom.X) - m_LeftBottom.X = point.X; - if (fabs(point.Y) != std::numeric_limits::infinity() && point.Y < m_LeftBottom.Y) - m_LeftBottom.Y = point.Y; - - if (fabs(point.X) != std::numeric_limits::infinity() && point.X > m_RightTop.X) - m_RightTop.X = point.X; - if (fabs(point.Y) != std::numeric_limits::infinity() && point.Y > m_RightTop.Y) - m_RightTop.Y = point.Y; - } - - m_EqualY = m_RightTop.Y == m_LeftBottom.Y; - if (m_EqualY) - m_RightTop.Y += 1; - m_EqualX = m_RightTop.X == m_LeftBottom.X; - if (m_EqualX) - m_RightTop.X += 1; -} Property changes on: ps/trunk/source/gui/CChart.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CList.h =================================================================== --- ps/trunk/source/gui/CList.h (revision 23027) +++ ps/trunk/source/gui/CList.h (nonexistent) @@ -1,151 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CLIST -#define INCLUDED_CLIST - -#include "gui/CGUIList.h" -#include "gui/CGUISprite.h" -#include "gui/IGUIScrollBarOwner.h" -#include "gui/IGUITextOwner.h" - -#include - -/** - * Create a list of elements, where one can be selected - * by the user. The control will use a pre-processed - * text-object for each element, which will be managed - * by the IGUITextOwner structure. - * - * A scroll-bar will appear when needed. This will be - * achieved with the IGUIScrollBarOwner structure. - */ -class CList : public IGUIObject, public IGUIScrollBarOwner, public IGUITextOwner -{ - GUI_OBJECT(CList) - -public: - CList(CGUI& pGUI); - virtual ~CList(); - - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - /** - * @see IGUIObject#UpdateCachedSize() - */ - virtual void UpdateCachedSize(); - - /** - * Adds an item last to the list. - */ - virtual void AddItem(const CStrW& str, const CStrW& data); - -protected: - - /** - * Sets up text, should be called every time changes has been - * made that can change the visual. - */ - virtual void SetupText(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * Handle events manually to catch keyboard inputting. - */ - virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev); - - /** - * Draws the List box - */ - virtual void Draw(); - - /** - * Easy select elements functions - */ - virtual void SelectNextElement(); - virtual void SelectPrevElement(); - virtual void SelectFirstElement(); - virtual void SelectLastElement(); - - /** - * Handle the \ tag. - */ - virtual bool HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile); - - // Called every time the auto-scrolling should be checked. - void UpdateAutoScroll(); - - // Extended drawing interface, this is so that classes built on the this one - // can use other sprite names. - virtual void DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor); - - // Get the area of the list. This is so that it can easily be changed, like in CDropDown - // where the area is not equal to m_CachedActualSize. - virtual CRect GetListRect() const { return m_CachedActualSize; } - - // Returns whether SetupText() has run since the last message was received - // (and thus whether list items have possibly changed). - virtual bool GetModified() const { return m_Modified; } - - /** - * List of each element's relative y position. Will be - * one larger than m_Items, because it will end with the - * bottom of the last element. First element will always - * be zero, but still stored for easy handling. - */ - std::vector m_ItemsYPositions; - - virtual int GetHoveredItem(); - - // Settings - float m_BufferZone; - CStrW m_Font; - bool m_ScrollBar; - CStr m_ScrollBarStyle; - CStrW m_SoundDisabled; - CStrW m_SoundSelected; - CGUISpriteInstance m_Sprite; - CGUISpriteInstance m_SpriteSelectArea; - i32 m_CellID; - EAlign m_TextAlign; - CGUIColor m_TextColor; - CGUIColor m_TextColorSelected; - i32 m_Selected; - bool m_AutoScroll; - i32 m_Hovered; - CGUIList m_List; - CGUIList m_ListData; - -private: - // Whether the list's items have been modified since last handling a message. - bool m_Modified; - - // Used for doubleclick registration - int m_PrevSelectedItem; - - // Last time a click on an item was issued - double m_LastItemClickTime; -}; - -#endif // INCLUDED_CLIST Property changes on: ps/trunk/source/gui/CList.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUISize.cpp =================================================================== --- ps/trunk/source/gui/CGUISize.cpp (revision 23027) +++ ps/trunk/source/gui/CGUISize.cpp (nonexistent) @@ -1,232 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CGUISize.h" - -#include "gui/scripting/JSInterface_GUISize.h" -#include "ps/CLogger.h" - -CGUISize::CGUISize() - : pixel(), percent() -{ -} - -CGUISize::CGUISize(const CRect& pixel, const CRect& percent) - : pixel(pixel), percent(percent) -{ -} - -CGUISize CGUISize::Full() -{ - return CGUISize(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100)); -} - -CRect CGUISize::GetSize(const CRect& parent) const -{ - // If it's a 0 0 100% 100% we need no calculations - if (percent == CRect(0.f, 0.f, 100.f, 100.f) && pixel == CRect()) - return parent; - - CRect client; - - // This should probably be cached and not calculated all the time for every object. - 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; -} - -bool CGUISize::FromString(const CStr& Value) -{ - /* - * GUISizes contain a left, top, right, and bottom - * for example: "50%-150 10%+9 50%+150 10%+25" means - * the left edge is at 50% minus 150 pixels, the top - * edge is at 10% plus 9 pixels, the right edge is at - * 50% plus 150 pixels, and the bottom edge is at 10% - * plus 25 pixels. - * All four coordinates are required and can be - * defined only in pixels, only in percents, or some - * combination of both. - */ - - // Check the input is only numeric - const char* input = Value.c_str(); - CStr buffer = ""; - unsigned int coord = 0; - float pixels[4] = {0, 0, 0, 0}; - float percents[4] = {0, 0, 0, 0}; - for (unsigned int i = 0; i < Value.length(); ++i) - { - switch (input[i]) - { - case '.': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - buffer.push_back(input[i]); - break; - case '+': - pixels[coord] += buffer.ToFloat(); - buffer = "+"; - break; - case '-': - pixels[coord] += buffer.ToFloat(); - buffer = "-"; - break; - case '%': - percents[coord] += buffer.ToFloat(); - buffer = ""; - break; - case ' ': - pixels[coord] += buffer.ToFloat(); - buffer = ""; - ++coord; - break; - default: - LOGERROR("CGUISize definition may only include numbers. Your input: '%s'", Value.c_str()); - return false; - } - if (coord > 3) - { - LOGERROR("Too many CGUISize parameters (4 max). Your input: '%s'", Value.c_str()); - return false; - } - } - - if (coord < 3) - { - LOGERROR("Too few CGUISize parameters (4 min). Your input: '%s'", Value.c_str()); - return false; - } - - // Now that we're at the end of the string, flush the remaining buffer. - pixels[coord] += buffer.ToFloat(); - - // Now store the coords in the right place - pixel.left = pixels[0]; - pixel.top = pixels[1]; - pixel.right = pixels[2]; - pixel.bottom = pixels[3]; - percent.left = percents[0]; - percent.top = percents[1]; - percent.right = percents[2]; - percent.bottom = percents[3]; - return true; -} - -void CGUISize::ToJSVal(JSContext* cx, JS::MutableHandleValue ret) const -{ - JSAutoRequest rq(cx); - ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - ret.setObjectOrNull(pScriptInterface->CreateCustomObject("GUISize")); - - if (!ret.isObject()) - { - JS_ReportError(cx, "CGUISize value is not an Object"); - return; - } - - JS::RootedObject obj(cx, &ret.toObject()); - if (!JS_InstanceOf(cx, obj, &JSI_GUISize::JSI_class, nullptr)) - { - JS_ReportError(cx, "CGUISize value is not a CGUISize class instance"); - return; - } - -#define P(x, y, z)\ - if (!pScriptInterface->SetProperty(ret, #z, x.y)) \ - { \ - JS_ReportError(cx, "Could not SetProperty '%s'", #z); \ - return; \ - } - P(pixel, left, left); - P(pixel, top, top); - P(pixel, right, right); - P(pixel, bottom, bottom); - P(percent, left, rleft); - P(percent, top, rtop); - P(percent, right, rright); - P(percent, bottom, rbottom); -#undef P -} - -bool CGUISize::FromJSVal(JSContext* cx, JS::HandleValue v) -{ - JSAutoRequest rq(cx); - ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - - if (v.isString()) - { - CStrW str; - if (!ScriptInterface::FromJSVal(cx, v, str)) - { - JS_ReportError(cx, "CGUISize could not read JS string"); - return false; - } - - if (!FromString(str.ToUTF8())) - { - JS_ReportError(cx, "CGUISize could not parse JS string"); - return false; - } - return true; - } - - if (!v.isObject()) - { - JS_ReportError(cx, "CGUISize value is not an String, nor Object"); - return false; - } - - JS::RootedObject obj(cx, &v.toObject()); - if (!JS_InstanceOf(cx, obj, &JSI_GUISize::JSI_class, nullptr)) - { - JS_ReportError(cx, "CGUISize value is not a CGUISize class instance"); - return false; - } - -#define P(x, y, z) \ - if (!pScriptInterface->GetProperty(v, #z, x.y))\ - {\ - JS_ReportError(cx, "CGUISize could not get object property '%s'", #z);\ - return false;\ - } - - P(pixel, left, left); - P(pixel, top, top); - P(pixel, right, right); - P(pixel, bottom, bottom); - P(percent, left, rleft); - P(percent, top, rtop); - P(percent, right, rright); - P(percent, bottom, rbottom); -#undef P - - return true; -} Property changes on: ps/trunk/source/gui/CGUISize.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CInput.cpp =================================================================== --- ps/trunk/source/gui/CInput.cpp (revision 23027) +++ ps/trunk/source/gui/CInput.cpp (nonexistent) @@ -1,2051 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CInput.h" - -#include "gui/CGUI.h" -#include "gui/CGUIScrollBarVertical.h" -#include "graphics/FontMetrics.h" -#include "graphics/ShaderManager.h" -#include "graphics/TextRenderer.h" -#include "lib/sysdep/clipboard.h" -#include "lib/timer.h" -#include "lib/utf8.h" -#include "ps/ConfigDB.h" -#include "ps/GameSetup/Config.h" -#include "ps/Globals.h" -#include "ps/Hotkey.h" -#include "renderer/Renderer.h" - -#include - -extern int g_yres; - -CInput::CInput(CGUI& pGUI) - : - IGUIObject(pGUI), - IGUIScrollBarOwner(*static_cast(this)), - m_iBufferPos(-1), - m_iBufferPos_Tail(-1), - m_SelectingText(), - m_HorizontalScroll(), - m_PrevTime(), - m_CursorVisState(true), - m_CursorBlinkRate(0.5), - m_ComposingText(), - m_iComposedLength(), - m_iComposedPos(), - m_iInsertPos(), - m_BufferPosition(), - m_BufferZone(), - m_Caption(), - m_CellID(), - m_Font(), - m_MaskChar(), - m_Mask(), - m_MaxLength(), - m_MultiLine(), - m_Readonly(), - m_ScrollBar(), - m_ScrollBarStyle(), - m_Sprite(), - m_SpriteSelectArea(), - m_TextColor(), - m_TextColorSelected() -{ - RegisterSetting("buffer_position", m_BufferPosition); - RegisterSetting("buffer_zone", m_BufferZone); - RegisterSetting("caption", m_Caption); - RegisterSetting("cell_id", m_CellID); - RegisterSetting("font", m_Font); - RegisterSetting("mask_char", m_MaskChar); - RegisterSetting("mask", m_Mask); - RegisterSetting("max_length", m_MaxLength); - RegisterSetting("multiline", m_MultiLine); - RegisterSetting("readonly", m_Readonly); - RegisterSetting("scrollbar", m_ScrollBar); - RegisterSetting("scrollbar_style", m_ScrollBarStyle); - RegisterSetting("sprite", m_Sprite); - RegisterSetting("sprite_selectarea", m_SpriteSelectArea); - RegisterSetting("textcolor", m_TextColor); - RegisterSetting("textcolor_selected", m_TextColorSelected); - - CFG_GET_VAL("gui.cursorblinkrate", m_CursorBlinkRate); - - CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI); - bar->SetRightAligned(true); - AddScrollBar(bar); -} - -CInput::~CInput() -{ -} - -void CInput::UpdateBufferPositionSetting() -{ - SetSetting("buffer_position", m_iBufferPos, false); -} - -void CInput::ClearComposedText() -{ - m_Caption.erase(m_iInsertPos, m_iComposedLength); - m_iBufferPos = m_iInsertPos; - UpdateBufferPositionSetting(); - m_iComposedLength = 0; - m_iComposedPos = 0; -} - -InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev) -{ - ENSURE(m_iBufferPos != -1); - - switch (ev->ev.type) - { - case SDL_HOTKEYDOWN: - { - if (m_ComposingText) - return IN_HANDLED; - - return ManuallyHandleHotkeyEvent(ev); - } - // SDL2 has a new method of text input that better supports Unicode and CJK - // see https://wiki.libsdl.org/Tutorials/TextInput - case SDL_TEXTINPUT: - { - if (m_Readonly) - return IN_PASS; - - // Text has been committed, either single key presses or through an IME - std::wstring text = wstring_from_utf8(ev->ev.text.text); - - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - - if (m_ComposingText) - { - ClearComposedText(); - m_ComposingText = false; - } - - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption.append(text); - else - m_Caption.insert(m_iBufferPos, text); - - UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); - - m_iBufferPos += text.length(); - UpdateBufferPositionSetting(); - m_iBufferPos_Tail = -1; - - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - - return IN_HANDLED; - } - case SDL_TEXTEDITING: - { - if (m_Readonly) - return IN_PASS; - - // Text is being composed with an IME - // TODO: indicate this by e.g. underlining the uncommitted text - const char* rawText = ev->ev.edit.text; - int rawLength = strlen(rawText); - std::wstring wtext = wstring_from_utf8(rawText); - - debug_printf("SDL_TEXTEDITING: text=%s, start=%d, length=%d\n", rawText, ev->ev.edit.start, ev->ev.edit.length); - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - - // Remember cursor position when text composition begins - if (!m_ComposingText) - m_iInsertPos = m_iBufferPos; - else - { - // Composed text is replaced each time - ClearComposedText(); - } - - m_ComposingText = ev->ev.edit.start != 0 || rawLength != 0; - if (m_ComposingText) - { - m_Caption.insert(m_iInsertPos, wtext); - - // The text buffer is limited to SDL_TEXTEDITINGEVENT_TEXT_SIZE bytes, yet start - // increases without limit, so don't let it advance beyond the composed text length - m_iComposedLength = wtext.length(); - m_iComposedPos = ev->ev.edit.start < m_iComposedLength ? ev->ev.edit.start : m_iComposedLength; - m_iBufferPos = m_iInsertPos + m_iComposedPos; - - // TODO: composed text selection - what does ev.edit.length do? - m_iBufferPos_Tail = -1; - } - - UpdateBufferPositionSetting(); - UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); - - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - - return IN_HANDLED; - } - case SDL_KEYDOWN: - { - if (m_ComposingText) - return IN_HANDLED; - - // Since the GUI framework doesn't handle to set settings - // in Unicode (CStrW), we'll simply retrieve the actual - // pointer and edit that. - SDL_Keycode keyCode = ev->ev.key.keysym.sym; - - ManuallyImmutableHandleKeyDownEvent(keyCode); - ManuallyMutableHandleKeyDownEvent(keyCode); - - UpdateBufferPositionSetting(); - return IN_HANDLED; - } - default: - { - return IN_PASS; - } - } -} - -void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode) -{ - if (m_Readonly) - return; - - wchar_t cooked = 0; - - switch (keyCode) - { - case SDLK_TAB: - { - SendEvent(GUIM_TAB, "tab"); - // Don't send a textedit event, because it should only - // be sent if the GUI control changes the text - break; - } - case SDLK_BACKSPACE: - { - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - else - { - m_iBufferPos_Tail = -1; - - if (m_Caption.empty() || m_iBufferPos == 0) - break; - - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption = m_Caption.Left(static_cast(m_Caption.length()) - 1); - else - m_Caption = - m_Caption.Left(m_iBufferPos - 1) + - m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); - - --m_iBufferPos; - - UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos); - } - - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - break; - } - case SDLK_DELETE: - { - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - else - { - if (m_Caption.empty() || m_iBufferPos == static_cast(m_Caption.length())) - break; - - m_Caption = - m_Caption.Left(m_iBufferPos) + - m_Caption.Right(static_cast(m_Caption.length()) - (m_iBufferPos + 1)); - - UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos); - } - - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - break; - } - case SDLK_KP_ENTER: - case SDLK_RETURN: - { - // 'Return' should do a Press event for single liners (e.g. submitting forms) - // otherwise a '\n' character will be added. - if (!m_MultiLine) - { - SendEvent(GUIM_PRESSED, "press"); - break; - } - - cooked = '\n'; // Change to '\n' and do default: - FALLTHROUGH; - } - default: // Insert a character - { - // In SDL2, we no longer get Unicode wchars via SDL_Keysym - // we use text input events instead and they provide UTF-8 chars - if (cooked == 0) - return; - - // check max length - if (m_MaxLength != 0 && static_cast(m_Caption.length()) >= m_MaxLength) - break; - - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - m_iBufferPos_Tail = -1; - - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption += cooked; - else - m_Caption = - m_Caption.Left(m_iBufferPos) + cooked + - m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); - - UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos + 1); - - ++m_iBufferPos; - - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - break; - } - } -} - -void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode) -{ - bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]; - - switch (keyCode) - { - case SDLK_HOME: - { - // If there's not a selection, we should create one now - if (!shiftKeyPressed) - { - // Make sure a selection isn't created. - m_iBufferPos_Tail = -1; - } - else if (!SelectingText()) - { - // Place tail at the current point: - m_iBufferPos_Tail = m_iBufferPos; - } - - m_iBufferPos = 0; - m_WantedX = 0.0f; - - UpdateAutoScroll(); - break; - } - case SDLK_END: - { - // If there's not a selection, we should create one now - if (!shiftKeyPressed) - { - // Make sure a selection isn't created. - m_iBufferPos_Tail = -1; - } - else if (!SelectingText()) - { - // Place tail at the current point: - m_iBufferPos_Tail = m_iBufferPos; - } - - m_iBufferPos = static_cast(m_Caption.length()); - m_WantedX = 0.0f; - - UpdateAutoScroll(); - break; - } - /** - * Conventions for Left/Right when text is selected: - * - * References: - * - * Visual Studio - * Visual Studio has the 'newer' approach, used by newer versions of - * things, and in newer applications. A left press will always place - * the pointer on the left edge of the selection, and then of course - * remove the selection. Right will do the exact same thing. - * If you have the pointer on the right edge and press right, it will - * in other words just remove the selection. - * - * Windows (eg. Notepad) - * A left press always takes the pointer a step to the left and - * removes the selection as if it were never there in the first place. - * Right of course does the same thing but to the right. - * - * I chose the Visual Studio convention. Used also in Word, gtk 2.0, MSN - * Messenger. - */ - case SDLK_LEFT: - { - m_WantedX = 0.f; - - if (shiftKeyPressed || !SelectingText()) - { - if (!shiftKeyPressed) - m_iBufferPos_Tail = -1; - else if (!SelectingText()) - m_iBufferPos_Tail = m_iBufferPos; - - if (m_iBufferPos > 0) - --m_iBufferPos; - } - else - { - if (m_iBufferPos_Tail < m_iBufferPos) - m_iBufferPos = m_iBufferPos_Tail; - - m_iBufferPos_Tail = -1; - } - - UpdateAutoScroll(); - break; - } - case SDLK_RIGHT: - { - m_WantedX = 0.0f; - - if (shiftKeyPressed || !SelectingText()) - { - if (!shiftKeyPressed) - m_iBufferPos_Tail = -1; - else if (!SelectingText()) - m_iBufferPos_Tail = m_iBufferPos; - - if (m_iBufferPos < static_cast(m_Caption.length())) - ++m_iBufferPos; - } - else - { - if (m_iBufferPos_Tail > m_iBufferPos) - m_iBufferPos = m_iBufferPos_Tail; - - m_iBufferPos_Tail = -1; - } - - UpdateAutoScroll(); - break; - } - /** - * Conventions for Up/Down when text is selected: - * - * References: - * - * Visual Studio - * Visual Studio has a very strange approach, down takes you below the - * selection to the next row, and up to the one prior to the whole - * selection. The weird part is that it is always aligned as the - * 'pointer'. I decided this is to much work for something that is - * a bit arbitrary - * - * Windows (eg. Notepad) - * Just like with left/right, the selection is destroyed and it moves - * just as if there never were a selection. - * - * I chose the Notepad convention even though I use the VS convention with - * left/right. - */ - case SDLK_UP: - { - if (!shiftKeyPressed) - m_iBufferPos_Tail = -1; - else if (!SelectingText()) - m_iBufferPos_Tail = m_iBufferPos; - - std::list::iterator current = m_CharacterPositions.begin(); - while (current != m_CharacterPositions.end()) - { - if (m_iBufferPos >= current->m_ListStart && - m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size()) - break; - - ++current; - } - - float pos_x; - if (m_iBufferPos - current->m_ListStart == 0) - pos_x = 0.f; - else - pos_x = current->m_ListOfX[m_iBufferPos - current->m_ListStart - 1]; - - if (m_WantedX > pos_x) - pos_x = m_WantedX; - - // Now change row: - if (current != m_CharacterPositions.begin()) - { - --current; - - // Find X-position: - m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX); - } - // else we can't move up - - UpdateAutoScroll(); - break; - } - case SDLK_DOWN: - { - if (!shiftKeyPressed) - m_iBufferPos_Tail = -1; - else if (!SelectingText()) - m_iBufferPos_Tail = m_iBufferPos; - - std::list::iterator current = m_CharacterPositions.begin(); - while (current != m_CharacterPositions.end()) - { - if (m_iBufferPos >= current->m_ListStart && - m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size()) - break; - - ++current; - } - - float pos_x; - - if (m_iBufferPos - current->m_ListStart == 0) - pos_x = 0.f; - else - pos_x = current->m_ListOfX[m_iBufferPos - current->m_ListStart - 1]; - - if (m_WantedX > pos_x) - pos_x = m_WantedX; - - // Now change row: - // Add first, so we can check if it's .end() - ++current; - if (current != m_CharacterPositions.end()) - { - // Find X-position: - m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX); - } - // else we can't move up - - UpdateAutoScroll(); - break; - } - case SDLK_PAGEUP: - { - GetScrollBar(0).ScrollMinusPlenty(); - UpdateAutoScroll(); - break; - } - case SDLK_PAGEDOWN: - { - GetScrollBar(0).ScrollPlusPlenty(); - UpdateAutoScroll(); - break; - } - default: - { - break; - } - } -} - -InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev) -{ - bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]; - - std::string hotkey = static_cast(ev->ev.user.data1); - - if (hotkey == "paste") - { - if (m_Readonly) - return IN_PASS; - - m_WantedX = 0.0f; - - wchar_t* text = sys_clipboard_get(); - if (text) - { - if (SelectingText()) - DeleteCurSelection(); - - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption += text; - else - m_Caption = - m_Caption.Left(m_iBufferPos) + text + - m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); - - UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); - - m_iBufferPos += (int)wcslen(text); - UpdateAutoScroll(); - UpdateBufferPositionSetting(); - - sys_clipboard_free(text); - - SendEvent(GUIM_TEXTEDIT, "textedit"); - } - - return IN_HANDLED; - } - else if (hotkey == "copy" || hotkey == "cut") - { - if (m_Readonly && hotkey == "cut") - return IN_PASS; - - m_WantedX = 0.0f; - - if (SelectingText()) - { - int virtualFrom; - int virtualTo; - - if (m_iBufferPos_Tail >= m_iBufferPos) - { - virtualFrom = m_iBufferPos; - virtualTo = m_iBufferPos_Tail; - } - else - { - virtualFrom = m_iBufferPos_Tail; - virtualTo = m_iBufferPos; - } - - CStrW text = m_Caption.Left(virtualTo).Right(virtualTo - virtualFrom); - - sys_clipboard_set(&text[0]); - - if (hotkey == "cut") - { - DeleteCurSelection(); - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - } - } - - return IN_HANDLED; - } - else if (hotkey == "text.delete.left") - { - if (m_Readonly) - return IN_PASS; - - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - - if (!m_Caption.empty() && m_iBufferPos != 0) - { - m_iBufferPos_Tail = m_iBufferPos; - CStrW searchString = m_Caption.Left(m_iBufferPos); - - // If we are starting in whitespace, adjust position until we get a non whitespace - while (m_iBufferPos > 0) - { - if (!iswspace(searchString[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - } - - // If we end up on a punctuation char we just delete it (treat punct like a word) - if (iswpunct(searchString[m_iBufferPos - 1])) - m_iBufferPos--; - else - { - // Now we are on a non white space character, adjust position to char after next whitespace char is found - while (m_iBufferPos > 0) - { - if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - } - } - - UpdateBufferPositionSetting(); - DeleteCurSelection(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - } - UpdateAutoScroll(); - return IN_HANDLED; - } - else if (hotkey == "text.delete.right") - { - if (m_Readonly) - return IN_PASS; - - m_WantedX = 0.0f; - - if (SelectingText()) - DeleteCurSelection(); - - if (!m_Caption.empty() && m_iBufferPos < static_cast(m_Caption.length())) - { - // Delete the word to the right of the cursor - m_iBufferPos_Tail = m_iBufferPos; - - // Delete chars to the right unit we hit whitespace - while (++m_iBufferPos < static_cast(m_Caption.length())) - { - if (iswspace(m_Caption[m_iBufferPos]) || iswpunct(m_Caption[m_iBufferPos])) - break; - } - - // Eliminate any whitespace behind the word we just deleted - while (m_iBufferPos < static_cast(m_Caption.length())) - { - if (!iswspace(m_Caption[m_iBufferPos])) - break; - - ++m_iBufferPos; - } - UpdateBufferPositionSetting(); - DeleteCurSelection(); - } - UpdateAutoScroll(); - SendEvent(GUIM_TEXTEDIT, "textedit"); - return IN_HANDLED; - } - else if (hotkey == "text.move.left") - { - m_WantedX = 0.0f; - - if (shiftKeyPressed || !SelectingText()) - { - if (!shiftKeyPressed) - m_iBufferPos_Tail = -1; - else if (!SelectingText()) - m_iBufferPos_Tail = m_iBufferPos; - - if (!m_Caption.empty() && m_iBufferPos != 0) - { - CStrW searchString = m_Caption.Left(m_iBufferPos); - - // If we are starting in whitespace, adjust position until we get a non whitespace - while (m_iBufferPos > 0) - { - if (!iswspace(searchString[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - } - - // If we end up on a puctuation char we just select it (treat punct like a word) - if (iswpunct(searchString[m_iBufferPos - 1])) - m_iBufferPos--; - else - { - // Now we are on a non white space character, adjust position to char after next whitespace char is found - while (m_iBufferPos > 0) - { - if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - } - } - } - } - else - { - if (m_iBufferPos_Tail < m_iBufferPos) - m_iBufferPos = m_iBufferPos_Tail; - - m_iBufferPos_Tail = -1; - } - - UpdateBufferPositionSetting(); - UpdateAutoScroll(); - - return IN_HANDLED; - } - else if (hotkey == "text.move.right") - { - m_WantedX = 0.0f; - - if (shiftKeyPressed || !SelectingText()) - { - if (!shiftKeyPressed) - m_iBufferPos_Tail = -1; - else if (!SelectingText()) - m_iBufferPos_Tail = m_iBufferPos; - - if (!m_Caption.empty() && m_iBufferPos < static_cast(m_Caption.length())) - { - // Select chars to the right until we hit whitespace - while (++m_iBufferPos < static_cast(m_Caption.length())) - { - if (iswspace(m_Caption[m_iBufferPos]) || iswpunct(m_Caption[m_iBufferPos])) - break; - } - - // Also select any whitespace following the word we just selected - while (m_iBufferPos < static_cast(m_Caption.length())) - { - if (!iswspace(m_Caption[m_iBufferPos])) - break; - - ++m_iBufferPos; - } - } - } - else - { - if (m_iBufferPos_Tail > m_iBufferPos) - m_iBufferPos = m_iBufferPos_Tail; - - m_iBufferPos_Tail = -1; - } - - UpdateBufferPositionSetting(); - UpdateAutoScroll(); - - return IN_HANDLED; - } - - return IN_PASS; -} - -void CInput::ResetStates() -{ - IGUIObject::ResetStates(); - IGUIScrollBarOwner::ResetStates(); -} - -void CInput::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - IGUIScrollBarOwner::HandleMessage(Message); - - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - { - // Update scroll-bar - // TODO Gee: (2004-09-01) Is this really updated each time it should? - if (m_ScrollBar && - (Message.value == "size" || - Message.value == "z" || - Message.value == "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 == "scrollbar_style") - GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); - - if (Message.value == "buffer_position") - { - m_iBufferPos = m_BufferPosition; - m_iBufferPos_Tail = -1; // position change resets selection - } - - if (Message.value == "size" || - Message.value == "z" || - Message.value == "font" || - Message.value == "absolute" || - Message.value == "caption" || - Message.value == "scrollbar" || - Message.value == "scrollbar_style") - { - UpdateText(); - } - - if (Message.value == "multiline") - { - if (!m_MultiLine) - GetScrollBar(0).SetLength(0.f); - else - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); - - UpdateText(); - } - - UpdateAutoScroll(); - - break; - } - case GUIM_MOUSE_PRESS_LEFT: - { - // Check if we're selecting the scrollbar - if (m_ScrollBar && - m_MultiLine && - GetScrollBar(0).GetStyle()) - { - if (m_pGUI.GetMousePos().x > m_CachedActualSize.right - GetScrollBar(0).GetStyle()->m_Width) - break; - } - - if (m_ComposingText) - break; - - // Okay, this section is about pressing the mouse and - // choosing where the point should be placed. For - // instance, if we press between a and b, the point - // should of course be placed accordingly. Other - // special cases are handled like the input box norms. - if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]) - m_iBufferPos = GetMouseHoveringTextPosition(); - else - m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition(); - - m_SelectingText = true; - - UpdateAutoScroll(); - - // If we immediately release the button it will just be seen as a click - // for the user though. - break; - } - case GUIM_MOUSE_DBLCLICK_LEFT: - { - if (m_ComposingText) - break; - - if (m_Caption.empty()) - break; - - m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition(); - - if (m_iBufferPos >= (int)m_Caption.length()) - m_iBufferPos = m_iBufferPos_Tail = m_Caption.length() - 1; - - // See if we are clicking over whitespace - if (iswspace(m_Caption[m_iBufferPos])) - { - // see if we are in a section of whitespace greater than one character - if ((m_iBufferPos + 1 < (int) m_Caption.length() && iswspace(m_Caption[m_iBufferPos + 1])) || - (m_iBufferPos - 1 > 0 && iswspace(m_Caption[m_iBufferPos - 1]))) - { - // - // We are clicking in an area with more than one whitespace character - // so we select both the word to the left and then the word to the right - // - // [1] First the left - // skip the whitespace - while (m_iBufferPos > 0) - { - if (!iswspace(m_Caption[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - } - // now go until we hit white space or punctuation - while (m_iBufferPos > 0) - { - if (iswspace(m_Caption[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - - if (iswpunct(m_Caption[m_iBufferPos])) - break; - } - - // [2] Then the right - // go right until we are not in whitespace - while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) - { - if (!iswspace(m_Caption[m_iBufferPos_Tail])) - break; - } - - if (m_iBufferPos_Tail == static_cast(m_Caption.length())) - break; - - // now go to the right until we hit whitespace or punctuation - while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) - { - if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) - break; - } - } - else - { - // single whitespace so select word to the right - while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) - { - if (!iswspace(m_Caption[m_iBufferPos_Tail])) - break; - } - - if (m_iBufferPos_Tail == static_cast(m_Caption.length())) - break; - - // Don't include the leading whitespace - m_iBufferPos = m_iBufferPos_Tail; - - // now go to the right until we hit whitespace or punctuation - while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) - { - if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) - break; - } - } - } - else - { - // clicked on non-whitespace so select current word - // go until we hit white space or punctuation - while (m_iBufferPos > 0) - { - if (iswspace(m_Caption[m_iBufferPos - 1])) - break; - - m_iBufferPos--; - - if (iswpunct(m_Caption[m_iBufferPos])) - break; - } - // go to the right until we hit whitespace or punctuation - while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) - if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) - break; - } - UpdateAutoScroll(); - break; - } - case GUIM_MOUSE_RELEASE_LEFT: - { - if (m_SelectingText) - m_SelectingText = false; - break; - } - case GUIM_MOUSE_MOTION: - { - // If we just pressed down and started to move before releasing - // this is one way of selecting larger portions of text. - if (m_SelectingText) - { - // Actually, first we need to re-check that the mouse button is - // really pressed (it can be released while outside the control. - if (!g_mouse_buttons[SDL_BUTTON_LEFT]) - m_SelectingText = false; - else - m_iBufferPos = GetMouseHoveringTextPosition(); - UpdateAutoScroll(); - } - break; - } - case GUIM_LOAD: - { - 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); - GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); - - UpdateText(); - UpdateAutoScroll(); - - break; - } - case GUIM_GOT_FOCUS: - { - m_iBufferPos = 0; - m_PrevTime = 0.0; - m_CursorVisState = false; - - // Tell the IME where to draw the candidate list - SDL_Rect rect; - rect.h = m_CachedActualSize.GetSize().cy; - rect.w = m_CachedActualSize.GetSize().cx; - rect.x = m_CachedActualSize.TopLeft().x; - rect.y = m_CachedActualSize.TopLeft().y; - SDL_SetTextInputRect(&rect); - SDL_StartTextInput(); - break; - } - case GUIM_LOST_FOCUS: - { - if (m_ComposingText) - { - // Simulate a final text editing event to clear the composition - SDL_Event_ evt; - evt.ev.type = SDL_TEXTEDITING; - evt.ev.edit.length = 0; - evt.ev.edit.start = 0; - evt.ev.edit.text[0] = 0; - ManuallyHandleEvent(&evt); - } - SDL_StopTextInput(); - - m_iBufferPos = -1; - m_iBufferPos_Tail = -1; - break; - } - default: - { - break; - } - } - UpdateBufferPositionSetting(); -} - -void CInput::UpdateCachedSize() -{ - // If an ancestor's size changed, this will let us intercept the change and - // update our scrollbar positions - - IGUIObject::UpdateCachedSize(); - - if (m_ScrollBar) - { - 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); - } -} - -void CInput::Draw() -{ - float bz = GetBufferedZ(); - - if (m_CursorBlinkRate > 0.0) - { - // check if the cursor visibility state needs to be changed - double currTime = timer_Time(); - if (currTime - m_PrevTime >= m_CursorBlinkRate) - { - m_CursorVisState = !m_CursorVisState; - m_PrevTime = currTime; - } - } - else - // should always be visible - m_CursorVisState = true; - - // First call draw on ScrollBarOwner - if (m_ScrollBar && m_MultiLine) - IGUIScrollBarOwner::Draw(); - - CStrIntern font_name(m_Font.ToUTF8()); - - wchar_t mask_char = L'*'; - if (m_Mask && m_MaskChar.length() > 0) - mask_char = m_MaskChar[0]; - - m_pGUI.DrawSprite(m_Sprite, m_CellID, bz, m_CachedActualSize); - - float scroll = 0.f; - if (m_ScrollBar && m_MultiLine) - scroll = GetScrollBar(0).GetPos(); - - CFontMetrics font(font_name); - - // We'll have to setup clipping manually, since we're doing the rendering manually. - CRect cliparea(m_CachedActualSize); - - // First we'll figure out the clipping area, which is the cached actual size - // substracted by an optional scrollbar - if (m_ScrollBar) - { - scroll = GetScrollBar(0).GetPos(); - - // substract scrollbar from cliparea - if (cliparea.right > GetScrollBar(0).GetOuterRect().left && - cliparea.right <= GetScrollBar(0).GetOuterRect().right) - cliparea.right = GetScrollBar(0).GetOuterRect().left; - - if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && - cliparea.left < GetScrollBar(0).GetOuterRect().right) - cliparea.left = GetScrollBar(0).GetOuterRect().right; - } - - if (cliparea != CRect()) - { - glEnable(GL_SCISSOR_TEST); - glScissor( - cliparea.left * g_GuiScale, - g_yres - cliparea.bottom * g_GuiScale, - cliparea.GetWidth() * g_GuiScale, - cliparea.GetHeight() * g_GuiScale); - } - - // These are useful later. - int VirtualFrom, VirtualTo; - - if (m_iBufferPos_Tail >= m_iBufferPos) - { - VirtualFrom = m_iBufferPos; - VirtualTo = m_iBufferPos_Tail; - } - else - { - VirtualFrom = m_iBufferPos_Tail; - VirtualTo = m_iBufferPos; - } - - // Get the height of this font. - float h = (float)font.GetHeight(); - float ls = (float)font.GetLineSpacing(); - - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); - - CTextRenderer textRenderer(tech->GetShader()); - textRenderer.Font(font_name); - - // Set the Z to somewhat more, so we can draw a selected area between the - // the control and the text. - textRenderer.Translate( - (float)(int)(m_CachedActualSize.left) + m_BufferZone, - (float)(int)(m_CachedActualSize.top+h) + m_BufferZone, - bz+0.1f); - - // U+FE33: PRESENTATION FORM FOR VERTICAL LOW LINE - // (sort of like a | which is aligned to the left of most characters) - - float buffered_y = -scroll + m_BufferZone; - - // When selecting larger areas, we need to draw a rectangle box - // around it, and this is to keep track of where the box - // started, because we need to follow the iteration until we - // reach the end, before we can actually draw it. - bool drawing_box = false; - float box_x = 0.f; - - float x_pointer = 0.f; - - // If we have a selecting box (i.e. when you have selected letters, not just when - // the pointer is between two letters) we need to process all letters once - // before we do it the second time and render all the text. We can't do it - // in the same loop because text will have been drawn, so it will disappear when - // drawn behind the text that has already been drawn. Confusing, well it's necessary - // (I think). - - if (SelectingText()) - { - // Now m_iBufferPos_Tail can be of both sides of m_iBufferPos, - // just like you can select from right to left, as you can - // left to right. Is there a difference? Yes, the pointer - // be placed accordingly, so that if you select shift and - // expand this selection, it will expand on appropriate side. - // Anyway, since the drawing procedure needs "To" to be - // greater than from, we need virtual values that might switch - // place. - - int VirtualFrom, VirtualTo; - - if (m_iBufferPos_Tail >= m_iBufferPos) - { - VirtualFrom = m_iBufferPos; - VirtualTo = m_iBufferPos_Tail; - } - else - { - VirtualFrom = m_iBufferPos_Tail; - VirtualTo = m_iBufferPos; - } - - - bool done = false; - for (std::list::const_iterator it = m_CharacterPositions.begin(); - it != m_CharacterPositions.end(); - ++it, buffered_y += ls, x_pointer = 0.f) - { - if (m_MultiLine && buffered_y > m_CachedActualSize.GetHeight()) - break; - - // We might as well use 'i' here to iterate, because we need it - // (often compared against ints, so don't make it size_t) - for (int i = 0; i < (int)it->m_ListOfX.size()+2; ++i) - { - if (it->m_ListStart + i == VirtualFrom) - { - // we won't actually draw it now, because we don't - // know the width of each glyph to that position. - // we need to go along with the iteration, and - // make a mark where the box started: - drawing_box = true; // will turn false when finally rendered. - - // Get current x position - box_x = x_pointer; - } - - const bool at_end = (i == (int)it->m_ListOfX.size()+1); - - if (drawing_box && (it->m_ListStart + i == VirtualTo || at_end)) - { - // Depending on if it's just a row change, or if it's - // the end of the select box, do slightly different things. - if (at_end) - { - if (it->m_ListStart + i != VirtualFrom) - // and actually add a white space! yes, this is done in any common input - x_pointer += font.GetCharacterWidth(L' '); - } - else - { - drawing_box = false; - done = true; - } - - CRect rect; - // Set 'rect' depending on if it's a multiline control, or a one-line control - if (m_MultiLine) - { - rect = CRect( - m_CachedActualSize.left + box_x + m_BufferZone, - m_CachedActualSize.top + buffered_y + (h - ls) / 2, - m_CachedActualSize.left + x_pointer + m_BufferZone, - m_CachedActualSize.top + buffered_y + (h + ls) / 2); - - if (rect.bottom < m_CachedActualSize.top) - continue; - - if (rect.top < m_CachedActualSize.top) - rect.top = m_CachedActualSize.top; - - if (rect.bottom > m_CachedActualSize.bottom) - rect.bottom = m_CachedActualSize.bottom; - } - else // if one-line - { - rect = CRect( - m_CachedActualSize.left + box_x + m_BufferZone - m_HorizontalScroll, - m_CachedActualSize.top + buffered_y + (h - ls) / 2, - m_CachedActualSize.left + x_pointer + m_BufferZone - m_HorizontalScroll, - m_CachedActualSize.top + buffered_y + (h + ls) / 2); - - if (rect.left < m_CachedActualSize.left) - rect.left = m_CachedActualSize.left; - - if (rect.right > m_CachedActualSize.right) - rect.right = m_CachedActualSize.right; - } - - m_pGUI.DrawSprite(m_SpriteSelectArea, m_CellID, bz + 0.05f, rect); - } - - if (i < (int)it->m_ListOfX.size()) - { - if (!m_Mask) - x_pointer += font.GetCharacterWidth(m_Caption[it->m_ListStart + i]); - else - x_pointer += font.GetCharacterWidth(mask_char); - } - } - - if (done) - break; - - // If we're about to draw a box, and all of a sudden changes - // line, we need to draw that line's box, and then reset - // the box drawing to the beginning of the new line. - if (drawing_box) - box_x = 0.f; - } - } - - // Reset some from previous run - buffered_y = -scroll; - - // Setup initial color (then it might change and change back, when drawing selected area) - textRenderer.Color(m_TextColor); - - tech->BeginPass(); - - bool using_selected_color = false; - - for (std::list::const_iterator it = m_CharacterPositions.begin(); - it != m_CharacterPositions.end(); - ++it, buffered_y += ls) - { - if (buffered_y + m_BufferZone >= -ls || !m_MultiLine) - { - if (m_MultiLine && buffered_y + m_BufferZone > m_CachedActualSize.GetHeight()) - break; - - CMatrix3D savedTransform = textRenderer.GetTransform(); - - // Text must always be drawn in integer values. So we have to convert scroll - if (m_MultiLine) - textRenderer.Translate(0.f, -(float)(int)scroll, 0.f); - else - textRenderer.Translate(-(float)(int)m_HorizontalScroll, 0.f, 0.f); - - // We might as well use 'i' here, because we need it - // (often compared against ints, so don't make it size_t) - for (int i = 0; i < (int)it->m_ListOfX.size()+1; ++i) - { - if (!m_MultiLine && i < (int)it->m_ListOfX.size()) - { - if (it->m_ListOfX[i] - m_HorizontalScroll < -m_BufferZone) - { - // We still need to translate the OpenGL matrix - if (i == 0) - textRenderer.Translate(it->m_ListOfX[i], 0.f, 0.f); - else - textRenderer.Translate(it->m_ListOfX[i] - it->m_ListOfX[i-1], 0.f, 0.f); - - continue; - } - } - - // End of selected area, change back color - if (SelectingText() && it->m_ListStart + i == VirtualTo) - { - using_selected_color = false; - textRenderer.Color(m_TextColor); - } - - // selecting only one, then we need only to draw a cursor. - if (i != (int)it->m_ListOfX.size() && it->m_ListStart + i == m_iBufferPos && m_CursorVisState) - textRenderer.Put(0.0f, 0.0f, L"_"); - - // Drawing selected area - if (SelectingText() && - it->m_ListStart + i >= VirtualFrom && - it->m_ListStart + i < VirtualTo && - !using_selected_color) - { - using_selected_color = true; - textRenderer.Color(m_TextColorSelected); - } - - if (i != (int)it->m_ListOfX.size()) - { - if (!m_Mask) - textRenderer.PrintfAdvance(L"%lc", m_Caption[it->m_ListStart + i]); - else - textRenderer.PrintfAdvance(L"%lc", mask_char); - } - - // check it's now outside a one-liner, then we'll break - if (!m_MultiLine && i < (int)it->m_ListOfX.size() && - it->m_ListOfX[i] - m_HorizontalScroll > m_CachedActualSize.GetWidth() - m_BufferZone) - break; - } - - if (it->m_ListStart + (int)it->m_ListOfX.size() == m_iBufferPos) - { - textRenderer.Color(m_TextColor); - if (m_CursorVisState) - textRenderer.PutAdvance(L"_"); - - if (using_selected_color) - textRenderer.Color(m_TextColorSelected); - } - - textRenderer.SetTransform(savedTransform); - } - - textRenderer.Translate(0.f, ls, 0.f); - } - - textRenderer.Render(); - - if (cliparea != CRect()) - glDisable(GL_SCISSOR_TEST); - - tech->EndPass(); -} - -void CInput::UpdateText(int from, int to_before, int to_after) -{ - CStrIntern font_name(m_Font.ToUTF8()); - - wchar_t mask_char = L'*'; - if (m_Mask && m_MaskChar.length() > 0) - mask_char = m_MaskChar[0]; - - // Ensure positions are valid after caption changes - m_iBufferPos = std::min(m_iBufferPos, static_cast(m_Caption.size())); - m_iBufferPos_Tail = std::min(m_iBufferPos_Tail, static_cast(m_Caption.size())); - UpdateBufferPositionSetting(); - - if (font_name.empty()) - { - // Destroy everything stored, there's no font, so there can be no data. - m_CharacterPositions.clear(); - return; - } - - SRow row; - row.m_ListStart = 0; - - int to = 0; // make sure it's initialized - - if (to_before == -1) - to = static_cast(m_Caption.length()); - - CFontMetrics font(font_name); - - std::list::iterator current_line; - - // Used to ... TODO - int check_point_row_start = -1; - int check_point_row_end = -1; - - // Reset - if (from == 0 && to_before == -1) - { - m_CharacterPositions.clear(); - current_line = m_CharacterPositions.begin(); - } - else - { - ENSURE(to_before != -1); - - std::list::iterator destroy_row_from; - std::list::iterator destroy_row_to; - // Used to check if the above has been set to anything, - // previously a comparison like: - // destroy_row_from == std::list::iterator() - // ... was used, but it didn't work with GCC. - bool destroy_row_from_used = false; - bool destroy_row_to_used = false; - - // Iterate, and remove everything between 'from' and 'to_before' - // actually remove the entire lines they are on, it'll all have - // to be redone. And when going along, we'll delete a row at a time - // when continuing to see how much more after 'to' we need to remake. - int i = 0; - for (std::list::iterator it = m_CharacterPositions.begin(); - it != m_CharacterPositions.end(); - ++it, ++i) - { - if (!destroy_row_from_used && it->m_ListStart > from) - { - // Destroy the previous line, and all to 'to_before' - destroy_row_from = it; - --destroy_row_from; - - destroy_row_from_used = true; - - // For the rare case that we might remove characters to a word - // so that it suddenly fits on the previous row, - // we need to by standards re-do the whole previous line too - // (if one exists) - if (destroy_row_from != m_CharacterPositions.begin()) - --destroy_row_from; - } - - if (!destroy_row_to_used && it->m_ListStart > to_before) - { - destroy_row_to = it; - destroy_row_to_used = true; - - // If it isn't the last row, we'll add another row to delete, - // just so we can see if the last restorted line is - // identical to what it was before. If it isn't, then we'll - // have to continue. - // 'check_point_row_start' is where we store how the that - // line looked. - if (destroy_row_to != m_CharacterPositions.end()) - { - check_point_row_start = destroy_row_to->m_ListStart; - check_point_row_end = check_point_row_start + (int)destroy_row_to->m_ListOfX.size(); - if (destroy_row_to->m_ListOfX.empty()) - ++check_point_row_end; - } - - ++destroy_row_to; - break; - } - } - - if (!destroy_row_from_used) - { - destroy_row_from = m_CharacterPositions.end(); - --destroy_row_from; - - // As usual, let's destroy another row back - if (destroy_row_from != m_CharacterPositions.begin()) - --destroy_row_from; - - current_line = destroy_row_from; - } - - if (!destroy_row_to_used) - { - destroy_row_to = m_CharacterPositions.end(); - check_point_row_start = -1; - } - - // set 'from' to the row we'll destroy from - // and 'to' to the row we'll destroy to - from = destroy_row_from->m_ListStart; - - if (destroy_row_to != m_CharacterPositions.end()) - to = destroy_row_to->m_ListStart; // notice it will iterate [from, to), so it will never reach to. - else - to = static_cast(m_Caption.length()); - - - // Setup the first row - row.m_ListStart = destroy_row_from->m_ListStart; - - std::list::iterator temp_it = destroy_row_to; - --temp_it; - - current_line = m_CharacterPositions.erase(destroy_row_from, destroy_row_to); - - // If there has been a change in number of characters - // we need to change all m_ListStart that comes after - // the interval we just destroyed. We'll change all - // values with the delta change of the string length. - int delta = to_after - to_before; - if (delta != 0) - { - for (std::list::iterator it = current_line; - it != m_CharacterPositions.end(); - ++it) - it->m_ListStart += delta; - - // Update our check point too! - check_point_row_start += delta; - check_point_row_end += delta; - - if (to != static_cast(m_Caption.length())) - to += delta; - } - } - - int last_word_started = from; - float x_pos = 0.f; - - //if (to_before != -1) - // return; - - for (int i = from; i < to; ++i) - { - if (m_Caption[i] == L'\n' && m_MultiLine) - { - if (i == to-1 && to != static_cast(m_Caption.length())) - break; // it will be added outside - - current_line = m_CharacterPositions.insert(current_line, row); - ++current_line; - - // Setup the next row: - row.m_ListOfX.clear(); - row.m_ListStart = i+1; - x_pos = 0.f; - } - else - { - if (m_Caption[i] == L' '/* || TODO Gee (2004-10-13): the '-' disappears, fix. - m_Caption[i] == L'-'*/) - last_word_started = i+1; - - if (!m_Mask) - x_pos += font.GetCharacterWidth(m_Caption[i]); - else - x_pos += font.GetCharacterWidth(mask_char); - - if (x_pos >= GetTextAreaWidth() && m_MultiLine) - { - // The following decides whether it will word-wrap a word, - // or if it's only one word on the line, where it has to - // break the word apart. - if (last_word_started == row.m_ListStart) - { - last_word_started = i; - row.m_ListOfX.resize(row.m_ListOfX.size() - (i-last_word_started)); - //row.m_ListOfX.push_back(x_pos); - //continue; - } - else - { - // regular word-wrap - row.m_ListOfX.resize(row.m_ListOfX.size() - (i-last_word_started+1)); - } - - // Now, create a new line: - // notice: when we enter a newline, you can stand with the cursor - // both before and after that character, being on different - // rows. With automatic word-wrapping, that is not possible. Which - // is intuitively correct. - - current_line = m_CharacterPositions.insert(current_line, row); - ++current_line; - - // Setup the next row: - row.m_ListOfX.clear(); - row.m_ListStart = last_word_started; - - i = last_word_started-1; - - x_pos = 0.f; - } - else - // Get width of this character: - row.m_ListOfX.push_back(x_pos); - } - - // Check if it's the last iteration, and we're not revising the whole string - // because in that case, more word-wrapping might be needed. - // also check if the current line isn't the end - if (to_before != -1 && i == to-1 && current_line != m_CharacterPositions.end()) - { - // check all rows and see if any existing - if (row.m_ListStart != check_point_row_start) - { - std::list::iterator destroy_row_from; - std::list::iterator destroy_row_to; - // Are used to check if the above has been set to anything, - // previously a comparison like: - // destroy_row_from == std::list::iterator() - // was used, but it didn't work with GCC. - bool destroy_row_from_used = false; - bool destroy_row_to_used = false; - - // Iterate, and remove everything between 'from' and 'to_before' - // actually remove the entire lines they are on, it'll all have - // to be redone. And when going along, we'll delete a row at a time - // when continuing to see how much more after 'to' we need to remake. - int i = 0; - for (std::list::iterator it = m_CharacterPositions.begin(); - it != m_CharacterPositions.end(); - ++it, ++i) - { - if (!destroy_row_from_used && it->m_ListStart > check_point_row_start) - { - // Destroy the previous line, and all to 'to_before' - //if (i >= 2) - // destroy_row_from = it-2; - //else - // destroy_row_from = it-1; - destroy_row_from = it; - destroy_row_from_used = true; - //--destroy_row_from; - } - - if (!destroy_row_to_used && it->m_ListStart > check_point_row_end) - { - destroy_row_to = it; - destroy_row_to_used = true; - - // If it isn't the last row, we'll add another row to delete, - // just so we can see if the last restorted line is - // identical to what it was before. If it isn't, then we'll - // have to continue. - // 'check_point_row_start' is where we store how the that - // line looked. - if (destroy_row_to != m_CharacterPositions.end()) - { - check_point_row_start = destroy_row_to->m_ListStart; - check_point_row_end = check_point_row_start + (int)destroy_row_to->m_ListOfX.size(); - if (destroy_row_to->m_ListOfX.empty()) - ++check_point_row_end; - } - else - check_point_row_start = check_point_row_end = -1; - - ++destroy_row_to; - break; - } - } - - if (!destroy_row_from_used) - { - destroy_row_from = m_CharacterPositions.end(); - --destroy_row_from; - - current_line = destroy_row_from; - } - - if (!destroy_row_to_used) - { - destroy_row_to = m_CharacterPositions.end(); - check_point_row_start = check_point_row_end = -1; - } - - if (destroy_row_to != m_CharacterPositions.end()) - to = destroy_row_to->m_ListStart; // notice it will iterate [from, to[, so it will never reach to. - else - to = static_cast(m_Caption.length()); - - - // Set current line, new rows will be added before current_line, so - // we'll choose the destroy_row_to, because it won't be deleted - // in the coming erase. - current_line = destroy_row_to; - - m_CharacterPositions.erase(destroy_row_from, destroy_row_to); - } - // else, the for loop will end naturally. - } - } - // This is kind of special, when we renew a some lines, then the last - // one will sometimes end with a space (' '), that really should - // be omitted when word-wrapping. So we'll check if the last row - // we'll add has got the same value as the next row. - if (current_line != m_CharacterPositions.end()) - { - if (row.m_ListStart + (int)row.m_ListOfX.size() == current_line->m_ListStart) - row.m_ListOfX.resize(row.m_ListOfX.size()-1); - } - - // add the final row (even if empty) - m_CharacterPositions.insert(current_line, row); - - if (m_ScrollBar) - { - GetScrollBar(0).SetScrollRange(m_CharacterPositions.size() * font.GetLineSpacing() + m_BufferZone * 2.f); - GetScrollBar(0).SetScrollSpace(m_CachedActualSize.GetHeight()); - } -} - -int CInput::GetMouseHoveringTextPosition() const -{ - if (m_CharacterPositions.empty()) - return 0; - - // Return position - int retPosition; - - std::list::const_iterator current = m_CharacterPositions.begin(); - - CPos mouse = m_pGUI.GetMousePos(); - - if (m_MultiLine) - { - float scroll = 0.f; - if (m_ScrollBar) - scroll = GetScrollBarPos(0); - - // Now get the height of the font. - // TODO: Get the real font - CFontMetrics font(CStrIntern(m_Font.ToUTF8())); - float spacing = (float)font.GetLineSpacing(); - - // Change mouse position relative to text. - mouse -= m_CachedActualSize.TopLeft(); - mouse.x -= m_BufferZone; - mouse.y += scroll - m_BufferZone; - - int row = (int)((mouse.y) / spacing); - - if (row < 0) - row = 0; - - if (row > (int)m_CharacterPositions.size()-1) - row = (int)m_CharacterPositions.size()-1; - - // TODO Gee (2004-11-21): Okay, I need a 'std::list' for some reasons, but I would really like to - // be able to get the specific element here. This is hopefully a temporary hack. - - for (int i = 0; i < row; ++i) - ++current; - } - else - { - // current is already set to begin, - // but we'll change the mouse.x to fit our horizontal scrolling - mouse -= m_CachedActualSize.TopLeft(); - mouse.x -= m_BufferZone - m_HorizontalScroll; - // mouse.y is moot - } - - retPosition = current->m_ListStart; - - // Okay, now loop through the glyphs to find the appropriate X position - float dummy; - retPosition += GetXTextPosition(current, mouse.x, dummy); - - return retPosition; -} - -// Does not process horizontal scrolling, 'x' must be modified before inputted. -int CInput::GetXTextPosition(const std::list::const_iterator& current, const float& x, float& wanted) const -{ - int ret = 0; - float previous = 0.f; - int i = 0; - - for (std::vector::const_iterator it = current->m_ListOfX.begin(); - it != current->m_ListOfX.end(); - ++it, ++i) - { - if (*it >= x) - { - if (x - previous >= *it - x) - ret += i+1; - else - ret += i; - - break; - } - previous = *it; - } - // If a position wasn't found, we will assume the last - // character of that line. - if (i == (int)current->m_ListOfX.size()) - { - ret += i; - wanted = x; - } - else - wanted = 0.f; - - return ret; -} - -void CInput::DeleteCurSelection() -{ - int virtualFrom; - int virtualTo; - - if (m_iBufferPos_Tail >= m_iBufferPos) - { - virtualFrom = m_iBufferPos; - virtualTo = m_iBufferPos_Tail; - } - else - { - virtualFrom = m_iBufferPos_Tail; - virtualTo = m_iBufferPos; - } - - m_Caption = - m_Caption.Left(virtualFrom) + - m_Caption.Right(static_cast(m_Caption.length()) - virtualTo); - - UpdateText(virtualFrom, virtualTo, virtualFrom); - - // Remove selection - m_iBufferPos_Tail = -1; - m_iBufferPos = virtualFrom; - UpdateBufferPositionSetting(); -} - -bool CInput::SelectingText() const -{ - return m_iBufferPos_Tail != -1 && - m_iBufferPos_Tail != m_iBufferPos; -} - -float CInput::GetTextAreaWidth() -{ - if (m_ScrollBar && GetScrollBar(0).GetStyle()) - return m_CachedActualSize.GetWidth() - m_BufferZone * 2.f - GetScrollBar(0).GetStyle()->m_Width; - - return m_CachedActualSize.GetWidth() - m_BufferZone * 2.f; -} - -void CInput::UpdateAutoScroll() -{ - // Autoscrolling up and down - if (m_MultiLine) - { - if (!m_ScrollBar) - return; - - const float scroll = GetScrollBar(0).GetPos(); - - // Now get the height of the font. - // TODO: Get the real font - CFontMetrics font(CStrIntern(m_Font.ToUTF8())); - float spacing = (float)font.GetLineSpacing(); - //float height = font.GetHeight(); - - // TODO Gee (2004-11-21): Okay, I need a 'std::list' for some reasons, but I would really like to - // be able to get the specific element here. This is hopefully a temporary hack. - - std::list::iterator current = m_CharacterPositions.begin(); - int row = 0; - while (current != m_CharacterPositions.end()) - { - if (m_iBufferPos >= current->m_ListStart && - m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size()) - break; - - ++current; - ++row; - } - - // If scrolling down - if (-scroll + static_cast(row + 1) * spacing + m_BufferZone * 2.f > m_CachedActualSize.GetHeight()) - { - // Scroll so the selected row is shown completely, also with m_BufferZone length to the edge. - GetScrollBar(0).SetPos(static_cast(row + 1) * spacing - m_CachedActualSize.GetHeight() + m_BufferZone * 2.f); - } - // If scrolling up - else if (-scroll + (float)row * spacing < 0.f) - { - // Scroll so the selected row is shown completely, also with m_BufferZone length to the edge. - GetScrollBar(0).SetPos((float)row * spacing); - } - } - else // autoscrolling left and right - { - // Get X position of position: - if (m_CharacterPositions.empty()) - return; - - float x_position = 0.f; - float x_total = 0.f; - if (!m_CharacterPositions.begin()->m_ListOfX.empty()) - { - - // Get position of m_iBufferPos - if ((int)m_CharacterPositions.begin()->m_ListOfX.size() >= m_iBufferPos && - m_iBufferPos > 0) - x_position = m_CharacterPositions.begin()->m_ListOfX[m_iBufferPos-1]; - - // Get complete length: - x_total = m_CharacterPositions.begin()->m_ListOfX[m_CharacterPositions.begin()->m_ListOfX.size()-1]; - } - - // Check if outside to the right - if (x_position - m_HorizontalScroll + m_BufferZone * 2.f > m_CachedActualSize.GetWidth()) - m_HorizontalScroll = x_position - m_CachedActualSize.GetWidth() + m_BufferZone * 2.f; - - // Check if outside to the left - if (x_position - m_HorizontalScroll < 0.f) - m_HorizontalScroll = x_position; - - // Check if the text doesn't even fill up to the right edge even though scrolling is done. - if (m_HorizontalScroll != 0.f && - x_total - m_HorizontalScroll + m_BufferZone * 2.f < m_CachedActualSize.GetWidth()) - m_HorizontalScroll = x_total - m_CachedActualSize.GetWidth() + m_BufferZone * 2.f; - - // Now this is the fail-safe, if x_total isn't even the length of the control, - // remove all scrolling - if (x_total + m_BufferZone * 2.f < m_CachedActualSize.GetWidth()) - m_HorizontalScroll = 0.f; - } -} Property changes on: ps/trunk/source/gui/CInput.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CCheckBox.h =================================================================== --- ps/trunk/source/gui/CCheckBox.h (revision 23027) +++ ps/trunk/source/gui/CCheckBox.h (nonexistent) @@ -1,61 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CCHECKBOX -#define INCLUDED_CCHECKBOX - -#include "gui/CGUISprite.h" -#include "gui/IGUIButtonBehavior.h" - -class CCheckBox : public IGUIObject, public IGUIButtonBehavior -{ - GUI_OBJECT(CCheckBox) - -public: - CCheckBox(CGUI& pGUI); - virtual ~CCheckBox(); - - /** - * @see IGUIObject#ResetStates() - */ - virtual void ResetStates(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - /** - * Draws the control - */ - virtual void Draw(); - -protected: - // Settings - i32 m_CellID; - bool m_Checked; - CGUISpriteInstance m_SpriteUnchecked; - CGUISpriteInstance m_SpriteUncheckedOver; - CGUISpriteInstance m_SpriteUncheckedPressed; - CGUISpriteInstance m_SpriteUncheckedDisabled; - CGUISpriteInstance m_SpriteChecked; - CGUISpriteInstance m_SpriteCheckedOver; - CGUISpriteInstance m_SpriteCheckedPressed; - CGUISpriteInstance m_SpriteCheckedDisabled; -}; - -#endif // INCLUDED_CCHECKBOX Property changes on: ps/trunk/source/gui/CCheckBox.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/GUItypes.h =================================================================== --- ps/trunk/source/gui/GUItypes.h (revision 23027) +++ ps/trunk/source/gui/GUItypes.h (nonexistent) @@ -1,50 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* -This file is used by all bits of GUI code that need to repeat some code -for a variety of types (to avoid repeating the list of types in half a dozen -places, and to make it much easier to add a new type). Just do - #define TYPE(T) your_code_involving_T; - #include "GUItypes.h" - #undef TYPE -to handle every possible type. -*/ - -#ifndef GUITYPE_IGNORE_COPYABLE -#include "gui/EAlign.h" -TYPE(bool) -TYPE(i32) -TYPE(u32) -TYPE(float) -TYPE(EAlign) -TYPE(EVAlign) -TYPE(CPos) -#endif - -#ifndef GUITYPE_IGNORE_NONCOPYABLE -#include "gui/CGUIList.h" -#include "gui/CGUISeries.h" -TYPE(CGUISize) -TYPE(CGUIColor) -TYPE(CGUIList) -TYPE(CGUISeries) -TYPE(CGUISpriteInstance) -TYPE(CGUIString) -TYPE(CStr) -TYPE(CStrW) -#endif Property changes on: ps/trunk/source/gui/GUItypes.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/MiniMap.cpp =================================================================== --- ps/trunk/source/gui/MiniMap.cpp (revision 23027) +++ ps/trunk/source/gui/MiniMap.cpp (nonexistent) @@ -1,711 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "MiniMap.h" - -#include "graphics/GameView.h" -#include "graphics/LOSTexture.h" -#include "graphics/MiniPatch.h" -#include "graphics/Terrain.h" -#include "graphics/TerrainTextureEntry.h" -#include "graphics/TerrainTextureManager.h" -#include "graphics/TerritoryTexture.h" -#include "gui/CGUI.h" -#include "gui/GUIManager.h" -#include "gui/GUIMatrix.h" -#include "lib/bits.h" -#include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" -#include "lib/timer.h" -#include "ps/ConfigDB.h" -#include "ps/Filesystem.h" -#include "ps/Game.h" -#include "ps/GameSetup/Config.h" -#include "ps/Profile.h" -#include "ps/World.h" -#include "ps/XML/Xeromyces.h" -#include "renderer/Renderer.h" -#include "renderer/RenderingOptions.h" -#include "renderer/WaterManager.h" -#include "scriptinterface/ScriptInterface.h" -#include "simulation2/components/ICmpMinimap.h" -#include "simulation2/Simulation2.h" -#include "simulation2/system/ParamNode.h" - -#include - -extern bool g_GameRestarted; - -// Set max drawn entities to UINT16_MAX for now, which is more than enough -// TODO: we should be cleverer about drawing them to reduce clutter -const u16 MAX_ENTITIES_DRAWN = 65535; - -static unsigned int ScaleColor(unsigned int color, float x) -{ - unsigned int r = unsigned(float(color & 0xff) * x); - unsigned int g = unsigned(float((color>>8) & 0xff) * x); - unsigned int b = unsigned(float((color>>16) & 0xff) * x); - return (0xff000000 | b | g<<8 | r<<16); -} - -CMiniMap::CMiniMap(CGUI& pGUI) : - IGUIObject(pGUI), - m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0), m_TerrainDirty(true), m_MapScale(1.f), - m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), - m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), m_WaterHeight(0.0) -{ - m_Clicking = false; - m_MouseHovering = false; - - // Register Relax NG validator - CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); - - // Get the maximum height for unit passage in water. - CParamNode externalParamNode; - CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder"); - const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses"); - if (pathingSettings.GetChild("default").IsOk() && pathingSettings.GetChild("default").GetChild("MaxWaterDepth").IsOk()) - m_ShallowPassageHeight = pathingSettings.GetChild("default").GetChild("MaxWaterDepth").ToFloat(); - else - m_ShallowPassageHeight = 0.0f; - - m_AttributePos.type = GL_FLOAT; - m_AttributePos.elems = 2; - m_VertexArray.AddAttribute(&m_AttributePos); - - m_AttributeColor.type = GL_UNSIGNED_BYTE; - m_AttributeColor.elems = 4; - m_VertexArray.AddAttribute(&m_AttributeColor); - - m_VertexArray.SetNumVertices(MAX_ENTITIES_DRAWN); - m_VertexArray.Layout(); - - m_IndexArray.SetNumVertices(MAX_ENTITIES_DRAWN); - m_IndexArray.Layout(); - VertexArrayIterator index = m_IndexArray.GetIterator(); - for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) - *index++ = i; - m_IndexArray.Upload(); - m_IndexArray.FreeBackingStore(); - - - VertexArrayIterator attrPos = m_AttributePos.GetIterator(); - VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); - for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) - { - (*attrColor)[0] = 0; - (*attrColor)[1] = 0; - (*attrColor)[2] = 0; - (*attrColor)[3] = 0; - ++attrColor; - - (*attrPos)[0] = -10000.0f; - (*attrPos)[1] = -10000.0f; - - ++attrPos; - - } - m_VertexArray.Upload(); - - double blinkDuration = 1.0; - - // Tests won't have config initialised - if (CConfigDB::IsInitialised()) - { - CFG_GET_VAL("gui.session.minimap.pingduration", m_PingDuration); - CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration); - } - m_HalfBlinkDuration = blinkDuration/2; -} - -CMiniMap::~CMiniMap() -{ - Destroy(); -} - -void CMiniMap::HandleMessage(SGUIMessage& Message) -{ - IGUIObject::HandleMessage(Message); - switch (Message.type) - { - case GUIM_MOUSE_PRESS_LEFT: - if (m_MouseHovering) - { - SetCameraPos(); - m_Clicking = true; - } - break; - case GUIM_MOUSE_RELEASE_LEFT: - if (m_MouseHovering && m_Clicking) - SetCameraPos(); - m_Clicking = false; - break; - case GUIM_MOUSE_DBLCLICK_LEFT: - if (m_MouseHovering && m_Clicking) - SetCameraPos(); - m_Clicking = false; - break; - case GUIM_MOUSE_ENTER: - m_MouseHovering = true; - break; - case GUIM_MOUSE_LEAVE: - m_Clicking = false; - m_MouseHovering = false; - break; - case GUIM_MOUSE_RELEASE_RIGHT: - CMiniMap::FireWorldClickEvent(SDL_BUTTON_RIGHT, 1); - break; - case GUIM_MOUSE_DBLCLICK_RIGHT: - CMiniMap::FireWorldClickEvent(SDL_BUTTON_RIGHT, 2); - break; - case GUIM_MOUSE_MOTION: - if (m_MouseHovering && m_Clicking) - SetCameraPos(); - break; - case GUIM_MOUSE_WHEEL_DOWN: - case GUIM_MOUSE_WHEEL_UP: - Message.Skip(); - break; - - default: - break; - } -} - -bool CMiniMap::IsMouseOver() const -{ - // Get the mouse position. - const CPos& mousePos = m_pGUI.GetMousePos(); - // Get the position of the center of the minimap. - CPos minimapCenter = CPos(m_CachedActualSize.left + m_CachedActualSize.GetWidth() / 2.0, m_CachedActualSize.bottom - m_CachedActualSize.GetHeight() / 2.0); - // Take the magnitude of the difference of the mouse position and minimap center. - double distFromCenter = sqrt(pow((mousePos.x - minimapCenter.x), 2) + pow((mousePos.y - minimapCenter.y), 2)); - // If the distance is less then the radius of the minimap (half the width) the mouse is over the minimap. - if (distFromCenter < m_CachedActualSize.GetWidth() / 2.0) - return true; - else - return false; -} - -void CMiniMap::GetMouseWorldCoordinates(float& x, float& z) const -{ - // Determine X and Z according to proportion of mouse position and minimap - - const CPos& mousePos = m_pGUI.GetMousePos(); - - float px = (mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth(); - float py = (m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight(); - - float angle = GetAngle(); - - // Scale world coordinates for shrunken square map - x = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(px-0.5) - sin(angle)*(py-0.5)) + 0.5); - z = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(py-0.5) + sin(angle)*(px-0.5)) + 0.5); -} - -void CMiniMap::SetCameraPos() -{ - CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); - - CVector3D target; - GetMouseWorldCoordinates(target.X, target.Z); - target.Y = terrain->GetExactGroundLevel(target.X, target.Z); - g_Game->GetView()->MoveCameraTarget(target); -} - -float CMiniMap::GetAngle() const -{ - CVector3D cameraIn = m_Camera->m_Orientation.GetIn(); - return -atan2(cameraIn.X, cameraIn.Z); -} - -void CMiniMap::FireWorldClickEvent(int UNUSED(button), int UNUSED(clicks)) -{ - JSContext* cx = g_GUI->GetActiveGUI()->GetScriptInterface()->GetContext(); - JSAutoRequest rq(cx); - - float x, z; - GetMouseWorldCoordinates(x, z); - - JS::RootedValue coords(cx); - ScriptInterface::CreateObject(cx, &coords, "x", x, "z", z); - - JS::AutoValueVector paramData(cx); - paramData.append(coords); - - ScriptEvent("worldclick", paramData); -} - -// This sets up and draws the rectangle on the minimap -// which represents the view of the camera in the world. -void CMiniMap::DrawViewRect(CMatrix3D transform) const -{ - // Compute the camera frustum intersected with a fixed-height plane. - // Use the water height as a fixed base height, which should be the lowest we can go - float h = g_Renderer.GetWaterManager()->m_WaterHeight; - const float width = m_CachedActualSize.GetWidth(); - const float height = m_CachedActualSize.GetHeight(); - const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize); - - CVector3D hitPt[4]; - hitPt[0] = m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h); - hitPt[1] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h); - hitPt[2] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h); - hitPt[3] = m_Camera->GetWorldCoordinates(0, 0, h); - - float ViewRect[4][2]; - for (int i = 0; i < 4; ++i) - { - // convert to minimap space - ViewRect[i][0] = (width * hitPt[i].X * invTileMapSize); - ViewRect[i][1] = (height * hitPt[i].Z * invTileMapSize); - } - - float viewVerts[] = { - ViewRect[0][0], -ViewRect[0][1], - ViewRect[1][0], -ViewRect[1][1], - ViewRect[2][0], -ViewRect[2][1], - ViewRect[3][0], -ViewRect[3][1] - }; - - // Enable Scissoring to restrict the rectangle to only the minimap. - glScissor( - m_CachedActualSize.left * g_GuiScale, - g_Renderer.GetHeight() - m_CachedActualSize.bottom * g_GuiScale, - width * g_GuiScale, - height * g_GuiScale); - glEnable(GL_SCISSOR_TEST); - glLineWidth(2.0f); - - CShaderDefines lineDefines; - lineDefines.Add(str_MINIMAP_LINE, str_1); - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), lineDefines); - tech->BeginPass(); - CShaderProgramPtr shader = tech->GetShader(); - shader->Uniform(str_transform, transform); - shader->Uniform(str_color, 1.0f, 0.3f, 0.3f, 1.0f); - - shader->VertexPointer(2, GL_FLOAT, 0, viewVerts); - shader->AssertPointersBound(); - - if (!g_Renderer.m_SkipSubmit) - glDrawArrays(GL_LINE_LOOP, 0, 4); - - tech->EndPass(); - - glLineWidth(1.0f); - glDisable(GL_SCISSOR_TEST); -} - -struct MinimapUnitVertex -{ - // This struct is copyable for convenience and because to move is to copy for primitives. - u8 r, g, b, a; - float x, y; -}; - -// Adds a vertex to the passed VertexArray -static void inline addVertex(const MinimapUnitVertex& v, - VertexArrayIterator& attrColor, - VertexArrayIterator& attrPos) -{ - (*attrColor)[0] = v.r; - (*attrColor)[1] = v.g; - (*attrColor)[2] = v.b; - (*attrColor)[3] = v.a; - ++attrColor; - - (*attrPos)[0] = v.x; - (*attrPos)[1] = v.y; - - ++attrPos; -} - - -void CMiniMap::DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const -{ - // Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m) - // Scale square maps to fit in circular minimap area - const float s = sin(angle) * m_MapScale; - const float c = cos(angle) * m_MapScale; - const float m = coordMax / 2.f; - - float quadTex[] = { - m*(-c + s + 1.f), m*(-c + -s + 1.f), - m*(c + s + 1.f), m*(-c + s + 1.f), - m*(c + -s + 1.f), m*(c + s + 1.f), - - m*(c + -s + 1.f), m*(c + s + 1.f), - m*(-c + -s + 1.f), m*(c + -s + 1.f), - m*(-c + s + 1.f), m*(-c + -s + 1.f) - }; - float quadVerts[] = { - x, y, z, - x2, y, z, - x2, y2, z, - - x2, y2, z, - x, y2, z, - x, y, z - }; - - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); - shader->VertexPointer(3, GL_FLOAT, 0, quadVerts); - shader->AssertPointersBound(); - - if (!g_Renderer.m_SkipSubmit) - glDrawArrays(GL_TRIANGLES, 0, 6); -} - -// TODO: render the minimap in a framebuffer and just draw the frambuffer texture -// most of the time, updating the framebuffer twice a frame. -// Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling -// (those operations cause a gpu sync, which slows down the way gpu works) -void CMiniMap::Draw() -{ - PROFILE3("render minimap"); - - // The terrain isn't actually initialized until the map is loaded, which - // happens when the game is started, so abort until then. - if (!g_Game || !g_Game->IsGameStarted()) - return; - - CSimulation2* sim = g_Game->GetSimulation2(); - CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY); - ENSURE(cmpRangeManager); - - // Set our globals in case they hadn't been set before - m_Camera = g_Game->GetView()->GetCamera(); - m_Terrain = g_Game->GetWorld()->GetTerrain(); - m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); - m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); - m_MapSize = m_Terrain->GetVerticesPerSide(); - m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); - m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); - - if (!m_TerrainTexture || g_GameRestarted) - CreateTextures(); - - - // only update 2x / second - // (note: since units only move a few pixels per second on the minimap, - // we can get away with infrequent updates; this is slow) - // TODO: Update all but camera at same speed as simulation - static double last_time; - const double cur_time = timer_Time(); - const bool doUpdate = cur_time - last_time > 0.5; - if (doUpdate) - { - last_time = cur_time; - if (m_TerrainDirty || m_WaterHeight != g_Renderer.GetWaterManager()->m_WaterHeight) - RebuildTerrainTexture(); - } - - const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; - const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; - const float z = GetBufferedZ(); - const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; - const float angle = GetAngle(); - const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); - - // Disable depth updates to prevent apparent z-fighting-related issues - // with some drivers causing units to get drawn behind the texture. - glDepthMask(0); - - CShaderProgramPtr shader; - CShaderTechniquePtr tech; - - CShaderDefines baseDefines; - baseDefines.Add(str_MINIMAP_BASE, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines); - tech->BeginPass(); - shader = tech->GetShader(); - - // Draw the main textured quad - shader->BindTexture(str_baseTex, m_TerrainTexture); - const CMatrix3D baseTransform = GetDefaultGuiMatrix(); - CMatrix3D baseTextureTransform; - baseTextureTransform.SetIdentity(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, baseTextureTransform); - - DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); - - // Draw territory boundaries - glEnable(GL_BLEND); - - CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); - - shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); - const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, *territoryTransform); - - DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); - tech->EndPass(); - - // Draw the LOS quad in black, using alpha values from the LOS texture - CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); - - CShaderDefines losDefines; - losDefines.Add(str_MINIMAP_LOS, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines); - tech->BeginPass(); - shader = tech->GetShader(); - shader->BindTexture(str_baseTex, losTexture.GetTexture()); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, *losTransform); - - DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); - tech->EndPass(); - - glDisable(GL_BLEND); - - PROFILE_START("minimap units"); - - CShaderDefines pointDefines; - pointDefines.Add(str_MINIMAP_POINT, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines); - tech->BeginPass(); - shader = tech->GetShader(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_pointSize, 3.f); - - CMatrix3D unitMatrix; - unitMatrix.SetIdentity(); - // Center the minimap on the origin of the axis of rotation. - unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f); - // Rotate the map. - unitMatrix.RotateZ(angle); - // Scale square maps to fit. - unitMatrix.Scale(unitScale, unitScale, 1.f); - // Move the minimap back to it's starting position. - unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f); - // Move the minimap to it's final location. - unitMatrix.Translate(x, y, z); - // Apply the gui matrix. - unitMatrix *= GetDefaultGuiMatrix(); - // Load the transform into the shader. - shader->Uniform(str_transform, unitMatrix); - - const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); - const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); - - CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); - - if (doUpdate) - { - VertexArrayIterator attrPos = m_AttributePos.GetIterator(); - VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); - - m_EntitiesDrawn = 0; - MinimapUnitVertex v; - std::vector pingingVertices; - pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); - - if (cur_time > m_NextBlinkTime) - { - m_BlinkState = !m_BlinkState; - m_NextBlinkTime = cur_time + m_HalfBlinkDuration; - } - - entity_pos_t posX, posZ; - for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) - { - ICmpMinimap* cmpMinimap = static_cast(it->second); - if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) - { - ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer()); - if (vis != ICmpRangeManager::VIS_HIDDEN) - { - v.a = 255; - v.x = posX.ToFloat() * sx; - v.y = -posZ.ToFloat() * sy; - - // Check minimap pinging to indicate something - if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration)) - { - v.r = 255; // ping color is white - v.g = 255; - v.b = 255; - pingingVertices.push_back(v); - } - else - { - addVertex(v, attrColor, attrPos); - ++m_EntitiesDrawn; - } - } - } - } - - // Add the pinged vertices at the end, so they are drawn on top - for (size_t v = 0; v < pingingVertices.size(); ++v) - { - addVertex(pingingVertices[v], attrColor, attrPos); - ++m_EntitiesDrawn; - } - - ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); - m_VertexArray.Upload(); - } - - m_VertexArray.PrepareForRendering(); - - if (m_EntitiesDrawn > 0) - { -#if !CONFIG2_GLES - if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER) - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - - u8* indexBase = m_IndexArray.Bind(); - u8* base = m_VertexArray.Bind(); - const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); - - shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); - shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); - shader->AssertPointersBound(); - - if (!g_Renderer.m_SkipSubmit) - glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); - - g_Renderer.GetStats().m_DrawCalls++; - CVertexBuffer::Unbind(); - -#if !CONFIG2_GLES - if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER) - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - } - - tech->EndPass(); - - DrawViewRect(unitMatrix); - - PROFILE_END("minimap units"); - - // Reset depth mask - glDepthMask(1); -} - -void CMiniMap::CreateTextures() -{ - Destroy(); - - // Create terrain texture - glGenTextures(1, &m_TerrainTexture); - g_Renderer.BindTexture(0, m_TerrainTexture); - - // Initialise texture with solid black, for the areas we don't - // overwrite with glTexSubImage2D later - u32* texData = new u32[m_TextureSize * m_TextureSize]; - for (ssize_t i = 0; i < m_TextureSize * m_TextureSize; ++i) - texData[i] = 0xFF000000; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); - delete[] texData; - - m_TerrainData = new u32[(m_MapSize - 1) * (m_MapSize - 1)]; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Rebuild and upload both of them - RebuildTerrainTexture(); -} - - -void CMiniMap::RebuildTerrainTexture() -{ - u32 x = 0; - u32 y = 0; - u32 w = m_MapSize - 1; - u32 h = m_MapSize - 1; - m_WaterHeight = g_Renderer.GetWaterManager()->m_WaterHeight; - - m_TerrainDirty = false; - - for (u32 j = 0; j < h; ++j) - { - u32* dataPtr = m_TerrainData + ((y + j) * (m_MapSize - 1)) + x; - for (u32 i = 0; i < w; ++i) - { - float avgHeight = ( m_Terrain->GetVertexGroundLevel((int)i, (int)j) - + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j) - + m_Terrain->GetVertexGroundLevel((int)i, (int)j+1) - + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j+1) - ) / 4.0f; - - if (avgHeight < m_WaterHeight && avgHeight > m_WaterHeight - m_ShallowPassageHeight) - { - // shallow water - *dataPtr++ = 0xffc09870; - } - else if (avgHeight < m_WaterHeight) - { - // Set water as constant color for consistency on different maps - *dataPtr++ = 0xffa07850; - } - else - { - int hmap = ((int)m_Terrain->GetHeightMap()[(y + j) * m_MapSize + x + i]) >> 8; - int val = (hmap / 3) + 170; - - u32 color = 0xFFFFFFFF; - - CMiniPatch* mp = m_Terrain->GetTile(x + i, y + j); - if (mp) - { - CTerrainTextureEntry* tex = mp->GetTextureEntry(); - if (tex) - { - // If the texture can't be loaded yet, set the dirty flags - // so we'll try regenerating the terrain texture again soon - if(!tex->GetTexture()->TryLoad()) - m_TerrainDirty = true; - - color = tex->GetBaseColor(); - } - } - - *dataPtr++ = ScaleColor(color, float(val) / 255.0f); - } - } - } - - // Upload the texture - g_Renderer.BindTexture(0, m_TerrainTexture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize - 1, m_MapSize - 1, GL_RGBA, GL_UNSIGNED_BYTE, m_TerrainData); -} - -void CMiniMap::Destroy() -{ - if (m_TerrainTexture) - { - glDeleteTextures(1, &m_TerrainTexture); - m_TerrainTexture = 0; - } - - SAFE_ARRAY_DELETE(m_TerrainData); -} Property changes on: ps/trunk/source/gui/MiniMap.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUIColor.h =================================================================== --- ps/trunk/source/gui/CGUIColor.h (revision 23027) +++ ps/trunk/source/gui/CGUIColor.h (nonexistent) @@ -1,61 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_GUICOLOR -#define INCLUDED_GUICOLOR - -#include "graphics/Color.h" -#include "ps/CStr.h" - -class CGUI; - -/** - * Same as the CColor class, but this one can also parse colors predefined in the GUI page (such as "yellow"). - */ -struct CGUIColor : CColor -{ - // Take advantage of compiler warnings if unintentionally copying this - NONCOPYABLE(CGUIColor); - - // Defines move semantics so that the structs using the class can use it. - MOVABLE(CGUIColor); - - CGUIColor() : CColor() {} - - CGUIColor(float r, float g, float b, float a) : CColor(r, g, b, a) {} - - /** - * Returns this color if it has been set, otherwise the given fallback color. - */ - const CGUIColor& operator||(const CGUIColor& fallback) const - { - if (*this) - return *this; - return fallback; - } - - /** - * Load color depending on current GUI page. - */ - bool ParseString(const CGUI& pGUI, const CStr& value, int defaultAlpha = 255); - - /** - * Ensure that all users check for predefined colors. - */ - bool ParseString(const CStr& value, int defaultAlpha = 255) = delete; -}; -#endif // INCLUDED_GUICOLOR Property changes on: ps/trunk/source/gui/CGUIColor.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CTooltip.h =================================================================== --- ps/trunk/source/gui/CTooltip.h (revision 23027) +++ ps/trunk/source/gui/CTooltip.h (nonexistent) @@ -1,68 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CTOOLTIP -#define INCLUDED_CTOOLTIP - -#include "gui/IGUITextOwner.h" -#include "gui/CGUISprite.h" -#include "gui/CGUIString.h" - -/** - * Dynamic tooltips. Similar to CText. - */ -class CTooltip : public IGUIObject, public IGUITextOwner -{ - GUI_OBJECT(CTooltip) - -public: - CTooltip(CGUI& pGUI); - virtual ~CTooltip(); - -protected: - void SetupText(); - - /** - * @see IGUIObject#UpdateCachedSize() - */ - void UpdateCachedSize(); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); - - virtual void Draw(); - - // Settings - float m_BufferZone; - CGUIString m_Caption; - CStrW m_Font; - CGUISpriteInstance m_Sprite; - i32 m_Delay; - CGUIColor m_TextColor; - float m_MaxWidth; - CPos m_Offset; - EVAlign m_Anchor; - EAlign m_TextAlign; - bool m_Independent; - CPos m_MousePos; - CStr m_UseObject; - bool m_HideObject; -}; - -#endif // INCLUDED_CTOOLTIP Property changes on: ps/trunk/source/gui/CTooltip.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/IGUIObject.h =================================================================== --- ps/trunk/source/gui/IGUIObject.h (revision 23027) +++ ps/trunk/source/gui/IGUIObject.h (nonexistent) @@ -1,536 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -/* - * The base class of an object. - * All objects are derived from this class. - * It's an abstract data type, so it can't be used per se. - * Also contains a Dummy object which is used for completely blank objects. - */ - -#ifndef INCLUDED_IGUIOBJECT -#define INCLUDED_IGUIOBJECT - -#include "gui/CGUISize.h" -#include "gui/scripting/JSInterface_IGUIObject.h" -#include "gui/SGUIMessage.h" -#include "lib/input.h" // just for IN_PASS -#include "ps/XML/Xeromyces.h" - -#include -#include -#include - -class CGUI; -class IGUIObject; -class IGUISetting; - -using map_pObjects = std::map; - -#define GUI_OBJECT(obj) \ -public: \ - static IGUIObject* ConstructObject(CGUI& pGUI) \ - { return new obj(pGUI); } - -/** - * GUI object such as a button or an input-box. - * Abstract data type ! - */ -class IGUIObject -{ - friend class CGUI; - - // Allow getProperty to access things like GetParent() - friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); - friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result); - friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp); - -public: - NONCOPYABLE(IGUIObject); - - IGUIObject(CGUI& pGUI); - virtual ~IGUIObject(); - - /** - * Checks if mouse is hovering this object. - * The mouse position is cached in CGUI. - * - * This function checks if the mouse is hovering the - * rectangle that the base setting "size" makes. - * Although it is virtual, so one could derive - * an object from CButton, which changes only this - * to checking the circle that "size" makes. - * - * @return true if mouse is hovering - */ - virtual bool IsMouseOver() const; - - /** - * Test if mouse position is over an icon - */ - virtual bool MouseOverIcon(); - - //-------------------------------------------------------- - /** @name Leaf Functions */ - //-------------------------------------------------------- - //@{ - - /// Get object name, name is unique - const CStr& GetName() const { return m_Name; } - - /// Get object name - void SetName(const CStr& Name) { m_Name = Name; } - - // Get Presentable name. - // Will change all internally set names to something like "" - CStr GetPresentableName() const; - - /** - * Adds object and its children to the map, it's name being the - * first part, and the second being itself. - * - * @param ObjectMap Adds this to the map_pObjects. - * - * @throws PSERROR_GUI_ObjectNeedsName Name is missing - * @throws PSERROR_GUI_NameAmbiguity Name is already taken - */ - void AddToPointersMap(map_pObjects& ObjectMap); - - /** - * Notice nothing will be returned or thrown if the child hasn't - * been inputted into the GUI yet. This is because that's were - * all is checked. Now we're just linking two objects, but - * it's when we're inputting them into the GUI we'll check - * validity! Notice also when adding it to the GUI this function - * will inevitably have been called by CGUI::AddObject which - * will catch the throw and return the error code. - * i.e. The user will never put in the situation wherein a throw - * must be caught, the GUI's internal error handling will be - * completely transparent to the interfacially sequential model. - * - * @param pChild Child to add - * - * @throws PSERROR_GUI from CGUI::UpdateObjects(). - */ - void AddChild(IGUIObject* pChild); - - /** - * Return all child objects of the current object. - */ - const std::vector& GetChildren() const { return m_Children; } - - //@} - //-------------------------------------------------------- - /** @name Settings Management */ - //-------------------------------------------------------- - //@{ - - /** - * Registers the given setting variables with the GUI object. - * Enable XML and JS to modify the given variable. - * - * @param Type Setting type - * @param Name Setting reference name - */ - template - void RegisterSetting(const CStr& Name, T& Value); - - /** - * Returns whether there is a setting with the given name registered. - * - * @param Setting setting name - * @return True if settings exist. - */ - bool SettingExists(const CStr& Setting) const; - - /** - * Get a mutable reference to the setting. - * If no such setting exists, an exception of type std::out_of_range is thrown. - * If the value is modified, there is no GUIM_SETTINGS_UPDATED message sent. - */ - template - T& GetSetting(const CStr& Setting); - - template - const T& GetSetting(const CStr& Setting) const; - - /** - * Set a setting by string, regardless of what type it is. - * Used to parse setting values from XML files. - * For example a CRect(10,10,20,20) is created from "10 10 20 20". - * Returns false if the conversion fails, otherwise true. - */ - bool SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage); - - /** - * Assigns the given value to the setting identified by the given name. - * Uses move semantics, so do not read from Value after this call. - * - * @param SendMessage If true, a GUIM_SETTINGS_UPDATED message will be broadcasted to all GUI objects. - */ - template - void SetSetting(const CStr& Setting, T& Value, const bool SendMessage); - - /** - * This variant will copy the value. - */ - template - void SetSetting(const CStr& Setting, const T& Value, const bool SendMessage); - - /** - * Returns whether this object is set to be hidden or ghost. - */ - bool IsEnabled() const; - - /** - * Returns whether this is object is set to be hidden. - */ - bool IsHidden() const; - - /** - * Returns whether this object is set to be hidden or ghost. - */ - bool IsHiddenOrGhost() const; - - /** - * Retrieves the configured sound filename from the given setting name and plays that once. - */ - void PlaySound(const CStrW& soundPath) const; - - /** - * Send event to this GUI object (HandleMessage and ScriptEvent) - * - * @param type Type of GUI message to be handled - * @param EventName String representation of event name - * @return IN_HANDLED if event was handled, or IN_PASS if skipped - */ - InReaction SendEvent(EGUIMessageType type, const CStr& EventName); - - /** - * All sizes are relative to resolution, and the calculation - * is not wanted in real time, therefore it is cached, update - * the cached size with this function. - */ - virtual void UpdateCachedSize(); - - /** - * Reset internal state of this object. - */ - virtual void ResetStates(); - - /** - * Set the script handler for a particular object-specific action - * - * @param Action Name of action - * @param Code Javascript code to execute when the action occurs - * @param pGUI GUI instance to associate the script with - */ - void RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI& pGUI); - - /** - * Inheriting classes may append JS functions to the JS object representing this class. - */ - virtual void RegisterScriptFunctions() {} - - /** - * Retrieves the JSObject representing this GUI object. - */ - JSObject* GetJSObject(); - - //@} -protected: - //-------------------------------------------------------- - /** @name Called by CGUI and friends - * - * Methods that the CGUI will call using - * its friendship, these should not - * be called by user. - * These functions' security are a lot - * what constitutes the GUI's - */ - //-------------------------------------------------------- - //@{ - -public: - /** - * This function is called with different messages - * for instance when the mouse enters the object. - * - * @param Message GUI Message - */ - virtual void HandleMessage(SGUIMessage& UNUSED(Message)) {} - - /** - * Calls an IGUIObject member function recursively on this object and its children. - * Aborts recursion at IGUIObjects that have the isRestricted function return true. - * The arguments of the callback function must be references. - */ - template - void RecurseObject(bool(IGUIObject::*isRestricted)() const, void(IGUIObject::*callbackFunction)(Args... args), Args&&... args) - { - if (!IsBaseObject()) - { - if (isRestricted && (this->*isRestricted)()) - return; - - (this->*callbackFunction)(args...); - } - - for (IGUIObject* const& obj : m_Children) - obj->RecurseObject(isRestricted, callbackFunction, args...); - } - -protected: - /** - * Draws the object. - * - * @throws PSERROR if any. But this will mostlikely be - * very rare since if an object is drawn unsuccessfully - * it'll probably only output in the Error log, and not - * disrupt the whole GUI drawing. - */ - virtual void Draw() = 0; - - /** - * Some objects need to handle the SDL_Event_ manually. - * For instance the input box. - * - * Only the object with focus will have this function called. - * - * Returns either IN_PASS or IN_HANDLED. If IN_HANDLED, then - * the key won't be passed on and processed by other handlers. - * This is used for keys that the GUI uses. - */ - virtual InReaction ManuallyHandleEvent(const SDL_Event_* UNUSED(ev)) { return IN_PASS; } - - /** - * Loads a style. - */ - void LoadStyle(const CStr& StyleName); - - /** - * Returns not the Z value, but the actual buffered Z value, i.e. if it's - * defined relative, then it will check its parent's Z value and add - * the relativity. - * - * @return Actual Z value on the screen. - */ - virtual float GetBufferedZ() const; - - /** - * Set parent of this object - */ - void SetParent(IGUIObject* pParent) { m_pParent = pParent; } - -public: - - CGUI& GetGUI() { return m_pGUI; } - const CGUI& GetGUI() const { return m_pGUI; } - - /** - * Take focus! - */ - void SetFocus(); - -protected: - /** - * Check if object is focused. - */ - bool IsFocused() const; - - /** - * NOTE! This will not just return m_pParent, when that is - * need use it! There is one exception to it, when the parent is - * the top-node (the object that isn't a real object), this - * will return nullptr, so that the top-node's children are - * seemingly parentless. - * - * @return Pointer to parent - */ - IGUIObject* GetParent() const; - - /** - * Handle additional children to the \-tag. In IGUIObject, this function does - * nothing. In CList and CDropDown, it handles the \, used to build the data. - * - * Returning false means the object doesn't recognize the child. Should be reported. - * Notice 'false' is default, because an object not using this function, should not - * have any additional children (and this function should never be called). - */ - virtual bool HandleAdditionalChildren(const XMBElement& UNUSED(child), CXeromyces* UNUSED(pFile)) - { - return false; - } - - /** - * Allow the GUI object to process after all child items were handled. - * Useful to avoid iterator invalidation with push_back calls. - */ - virtual void AdditionalChildrenHandled() {} - - /** - * Cached size, real size m_Size is actually dependent on resolution - * and can have different *real* outcomes, this is the real outcome - * cached to avoid slow calculations in real time. - */ - CRect m_CachedActualSize; - - /** - * Execute the script for a particular action. - * Does nothing if no script has been registered for that action. - * The mouse coordinates will be passed as the first argument. - * - * @param Action Name of action - */ - void ScriptEvent(const CStr& Action); - - /** - * Execute the script for a particular action. - * Does nothing if no script has been registered for that action. - * - * @param Action Name of action - * @param paramData JS::HandleValueArray arguments to pass to the event. - */ - void ScriptEvent(const CStr& Action, const JS::HandleValueArray& paramData); - - void SetScriptHandler(const CStr& Action, JS::HandleObject Function); - - /** - * Inputes the object that is currently hovered, this function - * updates this object accordingly (i.e. if it's the object - * being inputted one thing happens, and not, another). - * - * @param pMouseOver Object that is currently hovered, can be nullptr too! - */ - void UpdateMouseOver(IGUIObject* const& pMouseOver); - - //@} -private: - //-------------------------------------------------------- - /** @name Internal functions */ - //-------------------------------------------------------- - //@{ - - /** - * Creates the JS object representing this page upon first use. - */ - void CreateJSObject(); - - /** - * Updates some internal data depending on the setting changed. - */ - void PreSettingChange(const CStr& Setting); - void SettingChanged(const CStr& Setting, const bool SendMessage); - - /** - * Inputs a reference pointer, checks if the new inputted object - * if hovered, if so, then check if this's Z value is greater - * than the inputted object... If so then the object is closer - * and we'll replace the pointer with this. - * Also Notice input can be nullptr, which means the Z value demand - * is out. NOTICE you can't input nullptr as const so you'll have - * to set an object to nullptr. - * - * @param pObject Object pointer, can be either the old one, or - * the new one. - */ - void ChooseMouseOverAndClosest(IGUIObject*& pObject); - - /** - * Returns whether this is the object all other objects are descendants of. - */ - bool IsBaseObject() const; - - /** - * Returns whether this object is a child of the base object. - */ - bool IsRootObject() const; - - static void Trace(JSTracer* trc, void* data) - { - reinterpret_cast(data)->TraceMember(trc); - } - - void TraceMember(JSTracer* trc); - -// Variables -protected: - // Name of object - CStr m_Name; - - // Constructed on the heap, will be destroyed along with the the CGUI - std::vector m_Children; - - // Pointer to parent - IGUIObject* m_pParent; - - //This represents the last click time for each mouse button - double m_LastClickTime[6]; - - /** - * This is an array of true or false, each element is associated with - * a string representing a setting. Number of elements is equal to - * number of settings. - * - * A true means the setting has been manually set in the file when - * read. This is important to know because I don't want to force - * the user to include its \-XML-files first, so somehow - * the GUI needs to know which settings were set, and which is meant - * to. - */ - - // More variables - - // Is mouse hovering the object? used with the function IsMouseOver() - bool m_MouseHovering; - - /** - * Settings pool, all an object's settings are located here - * If a derived object has got more settings that the base - * settings, it's because they have a new version of the - * function SetupSettings(). - * - * @see SetupSettings() - */ -public: - std::map m_Settings; - -protected: - // An object can't function stand alone - CGUI& m_pGUI; - - // Internal storage for registered script handlers. - std::map > m_ScriptHandlers; - - // Cached JSObject representing this GUI object - JS::PersistentRootedObject m_JSObject; - - // Cache references to settings for performance - bool m_Enabled; - bool m_Hidden; - CGUISize m_Size; - CStr m_Style; - CStr m_Hotkey; - float m_Z; - bool m_Absolute; - bool m_Ghost; - float m_AspectRatio; - CStrW m_Tooltip; - CStr m_TooltipStyle; -}; - -#endif // INCLUDED_IGUIOBJECT Property changes on: ps/trunk/source/gui/IGUIObject.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CDropDown.cpp =================================================================== --- ps/trunk/source/gui/CDropDown.cpp (revision 23027) +++ ps/trunk/source/gui/CDropDown.cpp (nonexistent) @@ -1,505 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "CDropDown.h" - -#include "gui/CGUI.h" -#include "gui/CGUIColor.h" -#include "gui/CGUIList.h" -#include "gui/IGUIScrollBar.h" -#include "lib/external_libraries/libsdl.h" -#include "lib/timer.h" -#include "ps/Profile.h" - -CDropDown::CDropDown(CGUI& pGUI) - : CList(pGUI), - m_Open(), - m_HideScrollBar(), - m_ElementHighlight(-1), - m_ButtonWidth(), - m_DropDownSize(), - m_DropDownBuffer(), - m_MinimumVisibleItems(), - m_SoundClosed(), - m_SoundEnter(), - m_SoundLeave(), - m_SoundOpened(), - m_SpriteDisabled(), - m_SpriteList(), - m_Sprite2(), - m_Sprite2Over(), - m_Sprite2Pressed(), - m_Sprite2Disabled(), - m_TextColorDisabled(), - m_TextVAlign() -{ - RegisterSetting("button_width", m_ButtonWidth); - RegisterSetting("dropdown_size", m_DropDownSize); - RegisterSetting("dropdown_buffer", m_DropDownBuffer); - RegisterSetting("minimum_visible_items", m_MinimumVisibleItems); - RegisterSetting("sound_closed", m_SoundClosed); - RegisterSetting("sound_enter", m_SoundEnter); - RegisterSetting("sound_leave", m_SoundLeave); - RegisterSetting("sound_opened", m_SoundOpened); - // Setting "sprite" is registered by CList and used as the background - RegisterSetting("sprite_disabled", m_SpriteDisabled); - RegisterSetting("sprite_list", m_SpriteList); // Background of the drop down list - RegisterSetting("sprite2", m_Sprite2); // Button that sits to the right - RegisterSetting("sprite2_over", m_Sprite2Over); - RegisterSetting("sprite2_pressed", m_Sprite2Pressed); - RegisterSetting("sprite2_disabled", m_Sprite2Disabled); - RegisterSetting("textcolor_disabled", m_TextColorDisabled); - RegisterSetting("text_valign", m_TextVAlign); - // Add these in CList! And implement TODO - //RegisterSetting("textcolor_over"); - //RegisterSetting("textcolor_pressed"); - - // Scrollbar is forced to be true. - SetSetting("scrollbar", true, true); -} - -CDropDown::~CDropDown() -{ -} - -void CDropDown::SetupText() -{ - SetupListRect(); - CList::SetupText(); -} - -void CDropDown::UpdateCachedSize() -{ - CList::UpdateCachedSize(); - SetupText(); -} - -void CDropDown::HandleMessage(SGUIMessage& Message) -{ - // CList::HandleMessage(Message); placed after the switch! - - switch (Message.type) - { - case GUIM_SETTINGS_UPDATED: - { - // Update cached list rect - if (Message.value == "size" || - Message.value == "absolute" || - Message.value == "dropdown_size" || - Message.value == "dropdown_buffer" || - Message.value == "minimum_visible_items" || - Message.value == "scrollbar_style" || - Message.value == "button_width") - { - SetupListRect(); - } - - break; - } - - case GUIM_MOUSE_MOTION: - { - if (!m_Open) - break; - - CPos mouse = m_pGUI.GetMousePos(); - - if (!GetListRect().PointInside(mouse)) - break; - - const float scroll = m_ScrollBar ? GetScrollBar(0).GetPos() : 0.f; - - CRect rect = GetListRect(); - mouse.y += scroll; - int set = -1; - for (int i = 0; i < static_cast(m_List.m_Items.size()); ++i) - { - if (mouse.y >= rect.top + m_ItemsYPositions[i] && - mouse.y < rect.top + m_ItemsYPositions[i+1] && - // mouse is not over scroll-bar - (m_HideScrollBar || - mouse.x < GetScrollBar(0).GetOuterRect().left || - mouse.x > GetScrollBar(0).GetOuterRect().right)) - { - set = i; - } - } - - if (set != -1) - { - m_ElementHighlight = set; - //UpdateAutoScroll(); - } - - break; - } - - case GUIM_MOUSE_ENTER: - { - if (m_Enabled) - PlaySound(m_SoundEnter); - break; - } - - case GUIM_MOUSE_LEAVE: - { - m_ElementHighlight = m_Selected; - - if (m_Enabled) - PlaySound(m_SoundLeave); - break; - } - - // We can't inherent this routine from CList, because we need to include - // a mouse click to open the dropdown, also the coordinates are changed. - case GUIM_MOUSE_PRESS_LEFT: - { - if (!m_Enabled) - { - PlaySound(m_SoundDisabled); - break; - } - - if (!m_Open) - { - if (m_List.m_Items.empty()) - return; - - m_Open = true; - GetScrollBar(0).SetZ(GetBufferedZ()); - m_ElementHighlight = m_Selected; - - // Start at the position of the selected item, if possible. - GetScrollBar(0).SetPos(m_ItemsYPositions.empty() ? 0 : m_ItemsYPositions[m_ElementHighlight] - 60); - - PlaySound(m_SoundOpened); - return; // overshadow - } - else - { - const CPos& mouse = m_pGUI.GetMousePos(); - - // If the regular area is pressed, then abort, and close. - if (m_CachedActualSize.PointInside(mouse)) - { - m_Open = false; - GetScrollBar(0).SetZ(GetBufferedZ()); - PlaySound(m_SoundClosed); - return; // overshadow - } - - if (m_HideScrollBar || - mouse.x < GetScrollBar(0).GetOuterRect().left || - mouse.x > GetScrollBar(0).GetOuterRect().right || - mouse.y < GetListRect().top) - { - m_Open = false; - GetScrollBar(0).SetZ(GetBufferedZ()); - } - } - break; - } - - case GUIM_MOUSE_WHEEL_DOWN: - { - // Don't switch elements by scrolling when open, causes a confusing interaction between this and the scrollbar. - if (m_Open || !m_Enabled) - break; - - m_ElementHighlight = m_Selected; - - if (m_ElementHighlight + 1 >= (int)m_ItemsYPositions.size() - 1) - break; - - ++m_ElementHighlight; - SetSetting("selected", m_ElementHighlight, true); - break; - } - - case GUIM_MOUSE_WHEEL_UP: - { - // Don't switch elements by scrolling when open, causes a confusing interaction between this and the scrollbar. - if (m_Open || !m_Enabled) - break; - - m_ElementHighlight = m_Selected; - if (m_ElementHighlight - 1 < 0) - break; - - --m_ElementHighlight; - SetSetting("selected", m_ElementHighlight, true); - break; - } - - case GUIM_LOST_FOCUS: - { - if (m_Open) - PlaySound(m_SoundClosed); - - m_Open = false; - break; - } - - case GUIM_LOAD: - SetupListRect(); - break; - - default: - break; - } - - // Important that this is after, so that overshadowed implementations aren't processed - CList::HandleMessage(Message); - - // As HandleMessage functions return void, we need to manually verify - // whether the child list's items were modified. - if (CList::GetModified()) - SetupText(); -} - -InReaction CDropDown::ManuallyHandleEvent(const SDL_Event_* ev) -{ - InReaction result = IN_PASS; - bool update_highlight = false; - - if (ev->ev.type == SDL_KEYDOWN) - { - int szChar = ev->ev.key.keysym.sym; - - switch (szChar) - { - case '\r': - m_Open = false; - result = IN_HANDLED; - break; - - case SDLK_HOME: - case SDLK_END: - case SDLK_UP: - case SDLK_DOWN: - case SDLK_PAGEUP: - case SDLK_PAGEDOWN: - if (!m_Open) - return IN_PASS; - // Set current selected item to highlighted, before - // then really processing these in CList::ManuallyHandleEvent() - SetSetting("selected", m_ElementHighlight, true); - update_highlight = true; - break; - - default: - // If we have inputed a character try to get the closest element to it. - // TODO: not too nice and doesn't deal with dashes. - if (m_Open && ((szChar >= SDLK_a && szChar <= SDLK_z) || szChar == SDLK_SPACE - || (szChar >= SDLK_0 && szChar <= SDLK_9) - || (szChar >= SDLK_KP_0 && szChar <= SDLK_KP_9))) - { - // arbitrary 1 second limit to add to string or start fresh. - // maximal amount of characters is 100, which imo is far more than enough. - if (timer_Time() - m_TimeOfLastInput > 1.0 || m_InputBuffer.length() >= 100) - m_InputBuffer = szChar; - else - m_InputBuffer += szChar; - - m_TimeOfLastInput = timer_Time(); - - // let's look for the closest element - // basically it's alphabetic order and "as many letters as we can get". - int closest = -1; - int bestIndex = -1; - int difference = 1250; - for (int i = 0; i < static_cast(m_List.m_Items.size()); ++i) - { - int indexOfDifference = 0; - int diff = 0; - for (size_t j = 0; j < m_InputBuffer.length(); ++j) - { - diff = std::abs(static_cast(m_List.m_Items[i].GetRawString().LowerCase()[j]) - static_cast(m_InputBuffer[j])); - if (diff == 0) - indexOfDifference = j+1; - else - break; - } - if (indexOfDifference > bestIndex || (indexOfDifference >= bestIndex && diff < difference)) - { - bestIndex = indexOfDifference; - closest = i; - difference = diff; - } - } - // let's select the closest element. There should basically always be one. - if (closest != -1) - { - SetSetting("selected", closest, true); - update_highlight = true; - GetScrollBar(0).SetPos(m_ItemsYPositions[closest] - 60); - } - result = IN_HANDLED; - } - break; - } - } - - if (CList::ManuallyHandleEvent(ev) == IN_HANDLED) - result = IN_HANDLED; - - if (update_highlight) - m_ElementHighlight = m_Selected; - - return result; -} - -void CDropDown::SetupListRect() -{ - extern int g_yres; - extern float g_GuiScale; - const float yres = g_yres / g_GuiScale; - - if (m_ItemsYPositions.empty()) - { - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, m_CachedActualSize.bottom + m_DropDownBuffer + m_DropDownSize); - m_HideScrollBar = false; - } - // Too many items so use a scrollbar - else if (m_ItemsYPositions.back() > m_DropDownSize) - { - // Place items below if at least some items can be placed below - if (m_CachedActualSize.bottom + m_DropDownBuffer + m_DropDownSize <= yres) - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, m_CachedActualSize.bottom + m_DropDownBuffer + m_DropDownSize); - else if ((m_ItemsYPositions.size() > m_MinimumVisibleItems && yres - m_CachedActualSize.bottom - m_DropDownBuffer >= m_ItemsYPositions[m_MinimumVisibleItems]) || - m_CachedActualSize.top < yres - m_CachedActualSize.bottom) - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, yres); - // Not enough space below, thus place items above - else - m_CachedListRect = CRect(m_CachedActualSize.left, std::max(0.f, m_CachedActualSize.top - m_DropDownBuffer - m_DropDownSize), - m_CachedActualSize.right, m_CachedActualSize.top - m_DropDownBuffer); - - m_HideScrollBar = false; - } - else - { - // Enough space below, no scrollbar needed - if (m_CachedActualSize.bottom + m_DropDownBuffer + m_ItemsYPositions.back() <= yres) - { - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, m_CachedActualSize.bottom + m_DropDownBuffer + m_ItemsYPositions.back()); - m_HideScrollBar = true; - } - // Enough space below for some items, but not all, so place items below and use a scrollbar - else if ((m_ItemsYPositions.size() > m_MinimumVisibleItems && yres - m_CachedActualSize.bottom - m_DropDownBuffer >= m_ItemsYPositions[m_MinimumVisibleItems]) || - m_CachedActualSize.top < yres - m_CachedActualSize.bottom) - { - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, yres); - m_HideScrollBar = false; - } - // Not enough space below, thus place items above. Hide the scrollbar accordingly - else - { - m_CachedListRect = CRect(m_CachedActualSize.left, std::max(0.f, m_CachedActualSize.top - m_DropDownBuffer - m_ItemsYPositions.back()), - m_CachedActualSize.right, m_CachedActualSize.top - m_DropDownBuffer); - m_HideScrollBar = m_CachedActualSize.top > m_ItemsYPositions.back() + m_DropDownBuffer; - } - } -} - -CRect CDropDown::GetListRect() const -{ - return m_CachedListRect; -} - -bool CDropDown::IsMouseOver() const -{ - if (m_Open) - { - CRect rect(m_CachedActualSize.left, std::min(m_CachedActualSize.top, GetListRect().top), - m_CachedActualSize.right, std::max(m_CachedActualSize.bottom, GetListRect().bottom)); - return rect.PointInside(m_pGUI.GetMousePos()); - } - else - return m_CachedActualSize.PointInside(m_pGUI.GetMousePos()); -} - -void CDropDown::Draw() -{ - const float bz = GetBufferedZ(); - const CGUISpriteInstance& sprite = m_Enabled ? m_Sprite : m_SpriteDisabled; - - m_pGUI.DrawSprite(sprite, m_CellID, bz, m_CachedActualSize); - - if (m_ButtonWidth > 0.f) - { - CRect rect(m_CachedActualSize.right - m_ButtonWidth, m_CachedActualSize.top, - m_CachedActualSize.right, m_CachedActualSize.bottom); - - if (!m_Enabled) - { - m_pGUI.DrawSprite(m_Sprite2Disabled || m_Sprite2, m_CellID, bz + 0.05f, rect); - } - else if (m_Open) - { - m_pGUI.DrawSprite(m_Sprite2Pressed || m_Sprite2, m_CellID, bz + 0.05f, rect); - } - else if (m_MouseHovering) - { - m_pGUI.DrawSprite(m_Sprite2Over || m_Sprite2, m_CellID, bz + 0.05f, rect); - } - else - m_pGUI.DrawSprite(m_Sprite2, m_CellID, bz + 0.05f, rect); - } - - if (m_Selected != -1) // TODO: Maybe check validity completely? - { - CRect cliparea(m_CachedActualSize.left, m_CachedActualSize.top, - m_CachedActualSize.right - m_ButtonWidth, m_CachedActualSize.bottom); - - CPos pos(m_CachedActualSize.left, m_CachedActualSize.top); - DrawText(m_Selected, m_Enabled ? m_TextColorSelected : m_TextColorDisabled, pos, bz + 0.1f, cliparea); - } - - // Disable scrollbar during drawing without sending a setting-changed message - bool old = m_ScrollBar; - - if (m_Open) - { - // TODO: drawScrollbar as an argument of DrawList? - if (m_HideScrollBar) - m_ScrollBar = false; - - DrawList(m_ElementHighlight, m_SpriteList, m_SpriteSelectArea, m_TextColor); - - if (m_HideScrollBar) - m_ScrollBar = old; - } -} - -// When a dropdown list is opened, it needs to be visible above all the other -// controls on the page. The only way I can think of to do this is to increase -// its z value when opened, so that it's probably on top. -float CDropDown::GetBufferedZ() const -{ - float bz = CList::GetBufferedZ(); - if (m_Open) - return std::min(bz + 500.f, 1000.f); // TODO - don't use magic number for max z value - else - return bz; -} Property changes on: ps/trunk/source/gui/CDropDown.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/COList.h =================================================================== --- ps/trunk/source/gui/COList.h (revision 23027) +++ ps/trunk/source/gui/COList.h (nonexistent) @@ -1,91 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ -#ifndef INCLUDED_COLIST -#define INCLUDED_COLIST - -#include "CList.h" -#include "gui/CGUIColor.h" - -#include - -/** - * Represents a column. - */ -struct COListColumn -{ - // Avoid copying the strings. - NONCOPYABLE(COListColumn); - MOVABLE(COListColumn); - COListColumn() : m_Width(0), m_Hidden(false) {} - CGUIColor m_TextColor; - CStr m_Id; - float m_Width; - CStrW m_Heading; // CGUIString?? - CGUIList m_List; - bool m_Hidden; -}; - -/** - * Multi-column list. One row can be selected by the user. - * Individual cells are clipped if the contained text is too long. - * - * The list can be sorted dynamically by JS code when a - * heading is clicked. - * A scroll-bar will appear when needed. - */ -class COList : public CList -{ - GUI_OBJECT(COList) - -public: - COList(CGUI& pGUI); - -protected: - void SetupText(); - void HandleMessage(SGUIMessage& Message); - - /** - * Handle the \ tag. - */ - virtual bool HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile); - virtual void AdditionalChildrenHandled(); - - void DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor); - - virtual CRect GetListRect() const; - - /** - * Available columns. - */ - std::vector m_Columns; - - // Settings - CGUISpriteInstance m_SpriteHeading; - bool m_Sortable; - CStr m_SelectedColumn; - i32 m_SelectedColumnOrder; - CGUISpriteInstance m_SpriteAsc; - CGUISpriteInstance m_SpriteDesc; - CGUISpriteInstance m_SpriteNotSorted; - -private: - // Width of space available for columns - float m_TotalAvailableColumnWidth; - float m_HeadingHeight; -}; - -#endif // INCLUDED_COLIST Property changes on: ps/trunk/source/gui/COList.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUISeries.h =================================================================== --- ps/trunk/source/gui/CGUISeries.h (revision 23027) +++ ps/trunk/source/gui/CGUISeries.h (nonexistent) @@ -1,36 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. -* This file is part of 0 A.D. -* -* 0 A.D. is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 2 of the License, or -* (at your option) any later version. -* -* 0 A.D. is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 0 A.D. If not, see . -*/ - - -#ifndef INCLUDED_CGUISERIES -#define INCLUDED_CGUISERIES - -#include "maths/Vector2D.h" - -#include - -class CGUISeries -{ -public: - NONCOPYABLE(CGUISeries); - MOVABLE(CGUISeries); - CGUISeries() = default; - - std::vector> m_Series; -}; - -#endif // INCLUDED_CGUISERIES Property changes on: ps/trunk/source/gui/CGUISeries.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CImage.h =================================================================== --- ps/trunk/source/gui/CImage.h (revision 23027) +++ ps/trunk/source/gui/CImage.h (nonexistent) @@ -1,53 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CIMAGE -#define INCLUDED_CIMAGE - -#include "gui/CGUISprite.h" -#include "gui/IGUIObject.h" - -/** - * Object just for drawing a sprite. Like CText, without the - * possibility to draw text. - * - * Created, because I've seen the user being indecisive about - * what control to use in these situations. I've seen button - * without functionality used, and that is a lot of unnecessary - * overhead. That's why I thought I'd go with an intuitive - * control. - */ -class CImage : public IGUIObject -{ - GUI_OBJECT(CImage) - -public: - CImage(CGUI& pGUI); - virtual ~CImage(); - -protected: - /** - * Draws the Image - */ - virtual void Draw(); - - // Settings - CGUISpriteInstance m_Sprite; - i32 m_CellID; -}; - -#endif // INCLUDED_CIMAGE Property changes on: ps/trunk/source/gui/CImage.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/EAlign.h =================================================================== --- ps/trunk/source/gui/EAlign.h (revision 23027) +++ ps/trunk/source/gui/EAlign.h (nonexistent) @@ -1,24 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_EALIGN -#define INCLUDED_EALIGN - -enum EAlign { EAlign_Left, EAlign_Right, EAlign_Center }; -enum EVAlign { EVAlign_Top, EVAlign_Bottom, EVAlign_Center }; - -#endif // INCLUDED_EALIGN Property changes on: ps/trunk/source/gui/EAlign.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CRadioButton.h =================================================================== --- ps/trunk/source/gui/CRadioButton.h (revision 23027) +++ ps/trunk/source/gui/CRadioButton.h (nonexistent) @@ -1,42 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CRADIOBUTTON -#define INCLUDED_CRADIOBUTTON - -#include "CCheckBox.h" - -/** - * 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) - -public: - CRadioButton(CGUI& pGUI); - - /** - * @see IGUIObject#HandleMessage() - */ - virtual void HandleMessage(SGUIMessage& Message); -}; - -#endif // INCLUDED_CRADIOBUTTON Property changes on: ps/trunk/source/gui/CRadioButton.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/gui/CGUIString.h =================================================================== --- ps/trunk/source/gui/CGUIString.h (revision 23027) +++ ps/trunk/source/gui/CGUIString.h (nonexistent) @@ -1,219 +0,0 @@ -/* Copyright (C) 2019 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_CGUISTRING -#define INCLUDED_CGUISTRING - -#include "gui/CGUIText.h" -#include "ps/CStrIntern.h" - -#include -#include -#include - -class CGUI; - -/** - * String class, substitute 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 CGUIText is that - * CGUIString is a string-class that parses the tags - * when the value is set. The CGUIText 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: - /** - * 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 - { - /** - * 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, - TAG_INVALID - }; - - struct TagAttribute - { - std::wstring attrib; - std::wstring value; - }; - - /** - * Set tag from string - * - * @param tagtype TagType by string, like 'img' for [img] - * @return True if m_TagType was set. - */ - bool SetTagType(const CStrW& tagtype); - TagType GetTagType(const CStrW& tagtype) const; - - - /** - * In [b="Hello"][/b] - * m_TagType is TAG_B - */ - TagType m_TagType; - - /** - * In [b="Hello"][/b] - * m_TagValue is 'Hello' - */ - std::wstring m_TagValue; - - /** - * Some tags need an additional attributes - */ - std::vector m_TagAttributes; - }; - - /** - * 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; - }; - - /** - * All data generated in GenerateTextCall() - */ - struct SFeedback - { - // Avoid copying the vector and list containers. - NONCOPYABLE(SFeedback); - MOVABLE(SFeedback); - SFeedback() = default; - - // Constants - static const int Left = 0; - static const int Right = 1; - - /** - * Reset all member data. - */ - void Reset(); - - /** - * Image stacks, for left and right floating images. - */ - std::array, 2> m_Images; // left and right - - /** - * Text and Sprite Calls. - */ - std::vector m_TextCalls; - - // list for consistent mem addresses so that we can point to elements. - std::list 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 CStrW& str); - - /** - * Get String, with tags - */ - const CStrW& GetOriginalString() const { return m_OriginalString; } - - /** - * Get String, stripped of tags - */ - const CStrW& 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 pGUI Pointer to CGUI object making this call, for e.g. icon retrieval. - * @param Feedback contains all info that is generated. - * @param DefaultFont Default Font - * @param from From character n, - * @param to to character n. - * @param FirstLine Whether this is the first line of text, to calculate its height correctly - * @param pObject Only for Error outputting, optional! If nullptr - * then no Errors will be reported! Useful when you need - * to make several GenerateTextCall in different phases, - * it avoids duplicates. - */ - void GenerateTextCall(const CGUI& pGUI, SFeedback& Feedback, CStrIntern DefaultFont, const int& from, const int& to, const bool FirstLine, const IGUIObject* pObject = nullptr) const; - - /** - * Words - */ - std::vector m_Words; - -private: - /** - * TextChunks - */ - std::vector m_TextChunks; - - /** - * The full raw string. Stripped of tags. - */ - CStrW m_RawString; - - /** - * The original string value passed to SetValue. - */ - CStrW m_OriginalString; -}; - -#endif // INCLUDED_CGUISTRING Property changes on: ps/trunk/source/gui/CGUIString.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/build/premake/premake5.lua =================================================================== --- ps/trunk/build/premake/premake5.lua (revision 23027) +++ ps/trunk/build/premake/premake5.lua (revision 23028) @@ -1,1443 +1,1446 @@ newoption { trigger = "android", description = "Use non-working Android cross-compiling mode" } newoption { trigger = "atlas", description = "Include Atlas scenario editor projects" } newoption { trigger = "coverage", description = "Enable code coverage data collection (GCC only)" } newoption { trigger = "gles", description = "Use non-working OpenGL ES 2.0 mode" } newoption { trigger = "icc", description = "Use Intel C++ Compiler (Linux only; should use either \"--cc icc\" or --without-pch too, and then set CXX=icpc before calling make)" } newoption { trigger = "jenkins-tests", description = "Configure CxxTest to use the XmlPrinter runner which produces Jenkins-compatible output" } newoption { trigger = "minimal-flags", description = "Only set compiler/linker flags that are really needed. Has no effect on Windows builds" } newoption { trigger = "outpath", description = "Location for generated project files" } newoption { trigger = "with-system-mozjs45", description = "Search standard paths for libmozjs45, instead of using bundled copy" } newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" } newoption { trigger = "without-audio", description = "Disable use of OpenAL/Ogg/Vorbis APIs" } newoption { trigger = "without-lobby", description = "Disable the use of gloox and the multiplayer lobby" } newoption { trigger = "without-miniupnpc", description = "Disable use of miniupnpc for port forwarding" } newoption { trigger = "without-nvtt", description = "Disable use of NVTT" } newoption { trigger = "without-pch", description = "Disable generation and usage of precompiled headers" } newoption { trigger = "without-tests", description = "Disable generation of test projects" } -- Linux/BSD specific options newoption { trigger = "prefer-local-libs", description = "Prefer locally built libs. Any local libraries used must also be listed within a file within /etc/ld.so.conf.d so the dynamic linker can find them at runtime." } -- OS X specific options newoption { trigger = "macosx-bundle", description = "Enable OSX bundle, the argument is the bundle identifier string (e.g. com.wildfiregames.0ad)" } newoption { trigger = "macosx-version-min", description = "Set minimum required version of the OS X API, the build will possibly fail if an older SDK is used, while newer API functions will be weakly linked (i.e. resolved at runtime)" } newoption { trigger = "sysroot", description = "Set compiler system root path, used for building against a non-system SDK. For example /usr/local becomes SYSROOT/user/local" } -- Windows specific options newoption { trigger = "build-shared-glooxwrapper", description = "Rebuild glooxwrapper DLL for Windows. Requires the same compiler version that gloox was built with" } newoption { trigger = "use-shared-glooxwrapper", description = "Use prebuilt glooxwrapper DLL for Windows" } newoption { trigger = "large-address-aware", description = "Make the executable large address aware. Do not use for development, in order to spot memory issues easily" } -- Install options newoption { trigger = "bindir", description = "Directory for executables (typically '/usr/games'); default is to be relocatable" } newoption { trigger = "datadir", description = "Directory for data files (typically '/usr/share/games/0ad'); default is ../data/ relative to executable" } newoption { trigger = "libdir", description = "Directory for libraries (typically '/usr/lib/games/0ad'); default is ./ relative to executable" } -- Root directory of project checkout relative to this .lua file rootdir = "../.." dofile("extern_libs5.lua") -- detect compiler for non-Windows if os.istarget("macosx") then cc = "clang" elseif os.istarget("linux") and _OPTIONS["icc"] then cc = "icc" elseif not os.istarget("windows") then cc = os.getenv("CC") if cc == nil or cc == "" then local hasgcc = os.execute("which gcc > .gccpath") local f = io.open(".gccpath", "r") local gccpath = f:read("*line") f:close() os.execute("rm .gccpath") if gccpath == nil then cc = "clang" else cc = "gcc" end end end -- detect CPU architecture (simplistic, currently only supports x86, amd64 and ARM) arch = "x86" if _OPTIONS["android"] then arch = "arm" elseif os.istarget("windows") then if os.getenv("PROCESSOR_ARCHITECTURE") == "amd64" or os.getenv("PROCESSOR_ARCHITEW6432") == "amd64" then arch = "amd64" end else arch = os.getenv("HOSTTYPE") if arch == "x86_64" or arch == "amd64" then arch = "amd64" else os.execute(cc .. " -dumpmachine > .gccmachine.tmp") local f = io.open(".gccmachine.tmp", "r") local machine = f:read("*line") f:close() if string.find(machine, "x86_64") == 1 or string.find(machine, "amd64") == 1 then arch = "amd64" elseif string.find(machine, "i.86") == 1 then arch = "x86" elseif string.find(machine, "arm") == 1 then arch = "arm" elseif string.find(machine, "aarch64") == 1 then arch = "aarch64" else print("WARNING: Cannot determine architecture from GCC, assuming x86") end end end -- Set up the Workspace workspace "pyrogenesis" targetdir(rootdir.."/binaries/system") libdirs(rootdir.."/binaries/system") if not _OPTIONS["outpath"] then error("You must specify the 'outpath' parameter") end location(_OPTIONS["outpath"]) configurations { "Release", "Debug" } source_root = rootdir.."/source/" -- default for most projects - overridden by local in others -- Rationale: projects should not have any additional include paths except for -- those required by external libraries. Instead, we should always write the -- full relative path, e.g. #include "maths/Vector3d.h". This avoids confusion -- ("which file is meant?") and avoids enormous include path lists. -- projects: engine static libs, main exe, atlas, atlas frontends, test. -------------------------------------------------------------------------------- -- project helper functions -------------------------------------------------------------------------------- function project_set_target(project_name) -- Note: On Windows, ".exe" is added on the end, on unices the name is used directly local obj_dir_prefix = _OPTIONS["outpath"].."/obj/"..project_name.."_" filter "Debug" objdir(obj_dir_prefix.."Debug") targetsuffix("_dbg") filter "Release" objdir(obj_dir_prefix.."Release") filter { } end function project_set_build_flags() editandcontinue "Off" if not _OPTIONS["minimal-flags"] then symbols "On" end if cc ~= "icc" and (os.istarget("windows") or not _OPTIONS["minimal-flags"]) then -- adds the -Wall compiler flag warnings "Extra" -- this causes far too many warnings/remarks on ICC end -- disable Windows debug heap, since it makes malloc/free hugely slower when -- running inside a debugger if os.istarget("windows") then debugenvs { "_NO_DEBUG_HEAP=1" } end filter "Debug" defines { "DEBUG" } filter "Release" if os.istarget("windows") or not _OPTIONS["minimal-flags"] then optimize "Speed" end defines { "NDEBUG", "CONFIG_FINAL=1" } filter { } if _OPTIONS["gles"] then defines { "CONFIG2_GLES=1" } end if _OPTIONS["without-audio"] then defines { "CONFIG2_AUDIO=0" } end if _OPTIONS["without-nvtt"] then defines { "CONFIG2_NVTT=0" } end if _OPTIONS["without-lobby"] then defines { "CONFIG2_LOBBY=0" } end if _OPTIONS["without-miniupnpc"] then defines { "CONFIG2_MINIUPNPC=0" } end -- required for the lowlevel library. must be set from all projects that use it, otherwise it assumes it is -- being used as a DLL (which is currently not the case in 0ad) defines { "LIB_STATIC_LINK" } -- various platform-specific build flags if os.istarget("windows") then flags { "MultiProcessorCompile" } -- use native wchar_t type (not typedef to unsigned short) nativewchar "on" else -- *nix -- TODO, FIXME: This check is incorrect because it means that some additional flags will be added inside the "else" branch if the -- compiler is ICC and minimal-flags is specified (ticket: #2994) if cc == "icc" and not _OPTIONS["minimal-flags"] then buildoptions { "-w1", -- "-Wabi", -- "-Wp64", -- complains about OBJECT_TO_JSVAL which is annoying "-Wpointer-arith", "-Wreturn-type", -- "-Wshadow", "-Wuninitialized", "-Wunknown-pragmas", "-Wunused-function", "-wd1292" -- avoid lots of 'attribute "__nonnull__" ignored' } filter "Debug" buildoptions { "-O0" } -- ICC defaults to -O2 filter { } if os.istarget("macosx") then linkoptions { "-multiply_defined","suppress" } end else -- exclude most non-essential build options for minimal-flags if not _OPTIONS["minimal-flags"] then buildoptions { -- enable most of the standard warnings "-Wno-switch", -- enumeration value not handled in switch (this is sometimes useful, but results in lots of noise) "-Wno-reorder", -- order of initialization list in constructors (lots of noise) "-Wno-invalid-offsetof", -- offsetof on non-POD types (see comment in renderer/PatchRData.cpp) "-Wextra", "-Wno-missing-field-initializers", -- (this is common in external headers we can't fix) -- add some other useful warnings that need to be enabled explicitly "-Wunused-parameter", "-Wredundant-decls", -- (useful for finding some multiply-included header files) -- "-Wformat=2", -- (useful sometimes, but a bit noisy, so skip it by default) -- "-Wcast-qual", -- (useful for checking const-correctness, but a bit noisy, so skip it by default) "-Wnon-virtual-dtor", -- (sometimes noisy but finds real bugs) "-Wundef", -- (useful for finding macro name typos) -- enable security features (stack checking etc) that shouldn't have -- a significant effect on performance and can catch bugs "-fstack-protector-all", "-U_FORTIFY_SOURCE", -- (avoid redefinition warning if already defined) "-D_FORTIFY_SOURCE=2", -- always enable strict aliasing (useful in debug builds because of the warnings) "-fstrict-aliasing", -- don't omit frame pointers (for now), because performance will be impacted -- negatively by the way this breaks profilers more than it will be impacted -- positively by the optimisation "-fno-omit-frame-pointer" } if not _OPTIONS["without-pch"] then buildoptions { -- do something (?) so that ccache can handle compilation with PCH enabled -- (ccache 3.1+ also requires CCACHE_SLOPPINESS=time_macros for this to work) "-fpch-preprocess" } end if os.istarget("linux") or os.istarget("bsd") then buildoptions { "-fPIC" } linkoptions { "-Wl,--no-undefined", "-Wl,--as-needed", "-Wl,-z,relro" } end if arch == "x86" then buildoptions { -- To support intrinsics like __sync_bool_compare_and_swap on x86 -- we need to set -march to something that supports them (i686). -- We use pentium3 to also enable other features like mmx and sse, -- while tuning for generic to have good performance on every -- supported CPU. -- Note that all these features are already supported on amd64. "-march=pentium3 -mtune=generic" } end end buildoptions { -- Enable C++11 standard. "-std=c++0x" } if arch == "arm" then -- disable warnings about va_list ABI change and use -- compile-time flags for futher configuration. buildoptions { "-Wno-psabi" } if _OPTIONS["android"] then -- Android uses softfp, so we should too. buildoptions { "-mfloat-abi=softfp" } end end if _OPTIONS["coverage"] then buildoptions { "-fprofile-arcs", "-ftest-coverage" } links { "gcov" } end -- We don't want to require SSE2 everywhere yet, but OS X headers do -- require it (and Intel Macs always have it) so enable it here if os.istarget("macosx") then buildoptions { "-msse2" } end -- Check if SDK path should be used if _OPTIONS["sysroot"] then buildoptions { "-isysroot " .. _OPTIONS["sysroot"] } linkoptions { "-Wl,-syslibroot," .. _OPTIONS["sysroot"] } end -- On OS X, sometimes we need to specify the minimum API version to use if _OPTIONS["macosx-version-min"] then buildoptions { "-mmacosx-version-min=" .. _OPTIONS["macosx-version-min"] } -- clang and llvm-gcc look at mmacosx-version-min to determine link target -- and CRT version, and use it to set the macosx_version_min linker flag linkoptions { "-mmacosx-version-min=" .. _OPTIONS["macosx-version-min"] } end -- Check if we're building a bundle if _OPTIONS["macosx-bundle"] then defines { "BUNDLE_IDENTIFIER=" .. _OPTIONS["macosx-bundle"] } end -- On OS X, force using libc++ since it has better C++11 support, -- now required by the game if os.istarget("macosx") then buildoptions { "-stdlib=libc++" } linkoptions { "-stdlib=libc++" } end end buildoptions { -- Hide symbols in dynamic shared objects by default, for efficiency and for equivalence with -- Windows - they should be exported explicitly with __attribute__ ((visibility ("default"))) "-fvisibility=hidden" } if _OPTIONS["bindir"] then defines { "INSTALLED_BINDIR=" .. _OPTIONS["bindir"] } end if _OPTIONS["datadir"] then defines { "INSTALLED_DATADIR=" .. _OPTIONS["datadir"] } end if _OPTIONS["libdir"] then defines { "INSTALLED_LIBDIR=" .. _OPTIONS["libdir"] } end if os.istarget("linux") or os.istarget("bsd") then if _OPTIONS["prefer-local-libs"] then libdirs { "/usr/local/lib" } end -- To use our local shared libraries, they need to be found in the -- runtime dynamic linker path. Add their path to -rpath. if _OPTIONS["libdir"] then linkoptions {"-Wl,-rpath," .. _OPTIONS["libdir"] } else -- On FreeBSD we need to allow use of $ORIGIN if os.istarget("bsd") then linkoptions { "-Wl,-z,origin" } end -- Adding the executable path and taking care of correct escaping if _ACTION == "gmake" then linkoptions { "-Wl,-rpath,'$$ORIGIN'" } elseif _ACTION == "codeblocks" then linkoptions { "-Wl,-R\\\\$$$ORIGIN" } end end end end end -- create a project and set the attributes that are common to all projects. function project_create(project_name, target_type) project(project_name) language "C++" kind(target_type) filter "action:vs2013" toolset "v120_xp" filter "action:vs2015" toolset "v140_xp" filter {} project_set_target(project_name) project_set_build_flags() end -- OSX creates a .app bundle if the project type of the main application is set to "WindowedApp". -- We don't want this because this bundle would be broken (it lacks all the resources and external dependencies, Info.plist etc...) -- Windows opens a console in the background if it's set to ConsoleApp, which is not what we want. -- I didn't check if this setting matters for linux, but WindowedApp works there. function get_main_project_target_type() if _OPTIONS["android"] then return "SharedLib" elseif os.istarget("macosx") then return "ConsoleApp" else return "WindowedApp" end end -- source_root: rel_source_dirs and rel_include_dirs are relative to this directory -- rel_source_dirs: A table of subdirectories. All source files in these directories are added. -- rel_include_dirs: A table of subdirectories to be included. -- extra_params: table including zero or more of the following: -- * no_pch: If specified, no precompiled headers are used for this project. -- * pch_dir: If specified, this directory will be used for precompiled headers instead of the default -- /pch//. -- * extra_files: table of filenames (relative to source_root) to add to project -- * extra_links: table of library names to add to link step function project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) for i,v in pairs(rel_source_dirs) do local prefix = source_root..v.."/" files { prefix.."*.cpp", prefix.."*.h", prefix.."*.inl", prefix.."*.js", prefix.."*.asm", prefix.."*.mm" } end -- Put the project-specific PCH directory at the start of the -- include path, so '#include "precompiled.h"' will look in -- there first local pch_dir if not extra_params["pch_dir"] then pch_dir = source_root .. "pch/" .. project().name .. "/" else pch_dir = extra_params["pch_dir"] end includedirs { pch_dir } -- Precompiled Headers -- rationale: we need one PCH per static lib, since one global header would -- increase dependencies. To that end, we can either include them as -- "projectdir/precompiled.h", or add "source/PCH/projectdir" to the -- include path and put the PCH there. The latter is better because -- many projects contain several dirs and it's unclear where there the -- PCH should be stored. This way is also a bit easier to use in that -- source files always include "precompiled.h". -- Notes: -- * Visual Assist manages to use the project include path and can -- correctly open these files from the IDE. -- * precompiled.cpp (needed to "Create" the PCH) also goes in -- the abovementioned dir. if (not _OPTIONS["without-pch"] and not extra_params["no_pch"]) then filter "action:vs*" pchheader("precompiled.h") filter "action:xcode*" pchheader("../"..pch_dir.."precompiled.h") filter { "action:not vs*", "action:not xcode*" } pchheader(pch_dir.."precompiled.h") filter {} pchsource(pch_dir.."precompiled.cpp") defines { "USING_PCH" } files { pch_dir.."precompiled.h", pch_dir.."precompiled.cpp" } else flags { "NoPCH" } end -- next is source root dir, for absolute (nonrelative) includes -- (e.g. "lib/precompiled.h") includedirs { source_root } for i,v in pairs(rel_include_dirs) do includedirs { source_root .. v } end if extra_params["extra_files"] then for i,v in pairs(extra_params["extra_files"]) do -- .rc files are only needed on Windows if path.getextension(v) ~= ".rc" or os.istarget("windows") then files { source_root .. v } end end end if extra_params["extra_links"] then links { extra_params["extra_links"] } end end -- Add command-line options to set up the manifest dependencies for Windows -- (See lib/sysdep/os/win/manifest.cpp) function project_add_manifest() linkoptions { "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"" } end -------------------------------------------------------------------------------- -- engine static libraries -------------------------------------------------------------------------------- -- the engine is split up into several static libraries. this eases separate -- distribution of those components, reduces dependencies a bit, and can -- also speed up builds. -- more to the point, it is necessary to efficiently support a separate -- test executable that also includes much of the game code. -- names of all static libs created. automatically added to the -- main app project later (see explanation at end of this file) static_lib_names = {} static_lib_names_debug = {} static_lib_names_release = {} -- set up one of the static libraries into which the main engine code is split. -- extra_params: -- no_default_link: If specified, linking won't be done by default. -- For the rest of extra_params, see project_add_contents(). -- note: rel_source_dirs and rel_include_dirs are relative to global source_root. function setup_static_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) local target_type = "StaticLib" project_create(project_name, target_type) project_add_contents(source_root, rel_source_dirs, {}, extra_params) project_add_extern_libs(extern_libs, target_type) if not extra_params["no_default_link"] then table.insert(static_lib_names, project_name) end if os.istarget("windows") then rtti "off" elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end function setup_third_party_static_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) setup_static_lib_project(project_name, rel_source_dirs, extern_libs, extra_params) includedirs { source_root .. "third_party/" .. project_name .. "/include/" } end function setup_shared_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) local target_type = "SharedLib" project_create(project_name, target_type) project_add_contents(source_root, rel_source_dirs, {}, extra_params) project_add_extern_libs(extern_libs, target_type) if not extra_params["no_default_link"] then table.insert(static_lib_names, project_name) end if os.istarget("windows") then rtti "off" links { "delayimp" } elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end -- this is where the source tree is chopped up into static libs. -- can be changed very easily; just copy+paste a new setup_static_lib_project, -- or remove existing ones. static libs are automagically added to -- main_exe link step. function setup_all_libs () -- relative to global source_root. local source_dirs = {} -- names of external libraries used (see libraries_dir comment) local extern_libs = {} source_dirs = { "network", } extern_libs = { "spidermonkey", "enet", "boost", -- dragged in via server->simulation.h->random } if not _OPTIONS["without-miniupnpc"] then table.insert(extern_libs, "miniupnpc") end setup_static_lib_project("network", source_dirs, extern_libs, {}) source_dirs = { "third_party/tinygettext/src", } extern_libs = { "iconv", "boost", } setup_third_party_static_lib_project("tinygettext", source_dirs, extern_libs, { } ) -- it's an external library and we don't want to modify its source to fix warnings, so we just disable them to avoid noise in the compile output filter "action:vs*" buildoptions { "/wd4127", "/wd4309", "/wd4800", "/wd4100", "/wd4996", "/wd4099", "/wd4503" } filter {} if not _OPTIONS["without-lobby"] then source_dirs = { "lobby", "lobby/scripting", "i18n", "third_party/encryption" } extern_libs = { "spidermonkey", "boost", "enet", "gloox", "icu", "iconv", "libsodium", "tinygettext" } setup_static_lib_project("lobby", source_dirs, extern_libs, {}) if _OPTIONS["use-shared-glooxwrapper"] and not _OPTIONS["build-shared-glooxwrapper"] then table.insert(static_lib_names_debug, "glooxwrapper_dbg") table.insert(static_lib_names_release, "glooxwrapper") else source_dirs = { "lobby/glooxwrapper", } extern_libs = { "boost", "gloox", } if _OPTIONS["build-shared-glooxwrapper"] then setup_shared_lib_project("glooxwrapper", source_dirs, extern_libs, {}) else setup_static_lib_project("glooxwrapper", source_dirs, extern_libs, {}) end end else source_dirs = { "lobby/scripting", "third_party/encryption" } extern_libs = { "spidermonkey", "boost", "libsodium" } setup_static_lib_project("lobby", source_dirs, extern_libs, {}) files { source_root.."lobby/Globals.cpp" } end source_dirs = { "simulation2", "simulation2/components", "simulation2/helpers", "simulation2/scripting", "simulation2/serialization", "simulation2/system", "simulation2/testcomponents", } extern_libs = { "boost", "opengl", "spidermonkey", } setup_static_lib_project("simulation2", source_dirs, extern_libs, {}) source_dirs = { "scriptinterface", "scriptinterface/third_party" } extern_libs = { "boost", "spidermonkey", "valgrind", "sdl", } setup_static_lib_project("scriptinterface", source_dirs, extern_libs, {}) source_dirs = { "ps", "ps/scripting", "network/scripting", "ps/GameSetup", "ps/XML", "soundmanager", "soundmanager/data", "soundmanager/items", "soundmanager/scripting", "maths", "maths/scripting", "i18n", "i18n/scripting", "third_party/cppformat", } extern_libs = { "spidermonkey", "sdl", -- key definitions "libxml2", "opengl", "zlib", "boost", "enet", "libcurl", "tinygettext", "icu", "iconv", "libsodium", } if not _OPTIONS["without-audio"] then table.insert(extern_libs, "openal") table.insert(extern_libs, "vorbis") end setup_static_lib_project("engine", source_dirs, extern_libs, {}) source_dirs = { "graphics", "graphics/scripting", "renderer", "renderer/scripting", "third_party/mikktspace" } extern_libs = { "opengl", "sdl", -- key definitions "spidermonkey", -- for graphics/scripting "boost" } if not _OPTIONS["without-nvtt"] then table.insert(extern_libs, "nvtt") end setup_static_lib_project("graphics", source_dirs, extern_libs, {}) source_dirs = { "tools/atlas/GameInterface", "tools/atlas/GameInterface/Handlers" } extern_libs = { "boost", "sdl", -- key definitions "opengl", "spidermonkey" } setup_static_lib_project("atlas", source_dirs, extern_libs, {}) source_dirs = { "gui", - "gui/scripting", + "gui/ObjectTypes", + "gui/ObjectBases", + "gui/Scripting", + "gui/SettingTypes", "i18n" } extern_libs = { "spidermonkey", "sdl", -- key definitions "opengl", "boost", "enet", "tinygettext", "icu", "iconv", } if not _OPTIONS["without-audio"] then table.insert(extern_libs, "openal") end setup_static_lib_project("gui", source_dirs, extern_libs, {}) source_dirs = { "lib", "lib/adts", "lib/allocators", "lib/external_libraries", "lib/file", "lib/file/archive", "lib/file/common", "lib/file/io", "lib/file/vfs", "lib/pch", "lib/posix", "lib/res", "lib/res/graphics", "lib/sysdep", "lib/tex" } extern_libs = { "boost", "sdl", "openal", "opengl", "libpng", "zlib", "valgrind", "cxxtest", } -- CPU architecture-specific if arch == "amd64" then table.insert(source_dirs, "lib/sysdep/arch/amd64"); table.insert(source_dirs, "lib/sysdep/arch/x86_x64"); elseif arch == "x86" then table.insert(source_dirs, "lib/sysdep/arch/ia32"); table.insert(source_dirs, "lib/sysdep/arch/x86_x64"); elseif arch == "arm" then table.insert(source_dirs, "lib/sysdep/arch/arm"); elseif arch == "aarch64" then table.insert(source_dirs, "lib/sysdep/arch/aarch64"); end -- OS-specific sysdep_dirs = { linux = { "lib/sysdep/os/linux", "lib/sysdep/os/unix" }, -- note: RC file must be added to main_exe project. -- note: don't add "lib/sysdep/os/win/aken.cpp" because that must be compiled with the DDK. windows = { "lib/sysdep/os/win", "lib/sysdep/os/win/wposix", "lib/sysdep/os/win/whrt" }, macosx = { "lib/sysdep/os/osx", "lib/sysdep/os/unix" }, bsd = { "lib/sysdep/os/bsd", "lib/sysdep/os/unix", "lib/sysdep/os/unix/x" }, } for i,v in pairs(sysdep_dirs[os.target()]) do table.insert(source_dirs, v); end if os.istarget("linux") then if _OPTIONS["android"] then table.insert(source_dirs, "lib/sysdep/os/android") else table.insert(source_dirs, "lib/sysdep/os/unix/x") end end -- On OSX, disable precompiled headers because C++ files and Objective-C++ files are -- mixed in this project. To fix that, we would need per-file basis configuration which -- is not yet supported by the gmake action in premake. We should look into using gmake2. extra_params = {} if os.istarget("macosx") then extra_params = { no_pch = 1 } end -- runtime-library-specific if _ACTION == "vs2013" or _ACTION == "vs2015" then table.insert(source_dirs, "lib/sysdep/rtl/msc"); else table.insert(source_dirs, "lib/sysdep/rtl/gcc"); end setup_static_lib_project("lowlevel", source_dirs, extern_libs, extra_params) -- Third-party libraries that are built as part of the main project, -- not built externally and then linked source_dirs = { "third_party/mongoose", } extern_libs = { } setup_static_lib_project("mongoose", source_dirs, extern_libs, { no_pch = 1 }) -- CxxTest mock function support extern_libs = { "boost", "cxxtest", } -- 'real' implementations, to be linked against the main executable -- (files are added manually and not with setup_static_lib_project -- because not all files in the directory are included) setup_static_lib_project("mocks_real", {}, extern_libs, { no_default_link = 1, no_pch = 1 }) files { "mocks/*.h", source_root.."mocks/*_real.cpp" } -- 'test' implementations, to be linked against the test executable setup_static_lib_project("mocks_test", {}, extern_libs, { no_default_link = 1, no_pch = 1 }) files { source_root.."mocks/*.h", source_root.."mocks/*_test.cpp" } end -------------------------------------------------------------------------------- -- main EXE -------------------------------------------------------------------------------- -- used for main EXE as well as test used_extern_libs = { "opengl", "sdl", "libpng", "zlib", "spidermonkey", "libxml2", "boost", "cxxtest", "comsuppw", "enet", "libcurl", "tinygettext", "icu", "iconv", "libsodium", "valgrind", } if not os.istarget("windows") and not _OPTIONS["android"] and not os.istarget("macosx") then -- X11 should only be linked on *nix table.insert(used_extern_libs, "x11") table.insert(used_extern_libs, "xcursor") end if not _OPTIONS["without-audio"] then table.insert(used_extern_libs, "openal") table.insert(used_extern_libs, "vorbis") end if not _OPTIONS["without-nvtt"] then table.insert(used_extern_libs, "nvtt") end if not _OPTIONS["without-lobby"] then table.insert(used_extern_libs, "gloox") end if not _OPTIONS["without-miniupnpc"] then table.insert(used_extern_libs, "miniupnpc") end -- Bundles static libs together with main.cpp and builds game executable. function setup_main_exe () local target_type = get_main_project_target_type() project_create("pyrogenesis", target_type) filter "system:not macosx" linkgroups 'On' filter {} links { "mocks_real" } local extra_params = { extra_files = { "main.cpp" }, no_pch = 1 } project_add_contents(source_root, {}, {}, extra_params) project_add_extern_libs(used_extern_libs, target_type) dependson { "Collada" } -- Platform Specifics if os.istarget("windows") then files { source_root.."lib/sysdep/os/win/icon.rc" } -- from "lowlevel" static lib; must be added here to be linked in files { source_root.."lib/sysdep/os/win/error_dialog.rc" } rtti "off" linkoptions { -- wraps main thread in a __try block(see wseh.cpp). replace with mainCRTStartup if that's undesired. "/ENTRY:wseh_EntryPoint", -- see wstartup.h "/INCLUDE:_wstartup_InitAndRegisterShutdown", -- allow manual unload of delay-loaded DLLs "/DELAY:UNLOAD", } -- allow the executable to use more than 2GB of RAM. -- this should not be enabled during development, so that memory issues are easily spotted. if _OPTIONS["large-address-aware"] then linkoptions { "/LARGEADDRESSAWARE" } end -- see manifest.cpp project_add_manifest() elseif os.istarget("linux") or os.istarget("bsd") then if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then links { "rt" } end if _OPTIONS["android"] then -- NDK's STANDALONE-TOOLCHAIN.html says this is required linkoptions { "-Wl,--fix-cortex-a8" } links { "log" } end if os.istarget("linux") or os.getversion().description == "GNU/kFreeBSD" then links { -- Dynamic libraries (needed for linking for gold) "dl", } elseif os.istarget("bsd") then links { -- Needed for backtrace* on BSDs "execinfo", } end -- Threading support buildoptions { "-pthread" } if not _OPTIONS["android"] then linkoptions { "-pthread" } end -- For debug_resolve_symbol filter "Debug" linkoptions { "-rdynamic" } filter { } elseif os.istarget("macosx") then links { "pthread" } links { "ApplicationServices.framework", "Cocoa.framework", "CoreFoundation.framework" } if _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end end -------------------------------------------------------------------------------- -- atlas -------------------------------------------------------------------------------- -- setup a typical Atlas component project -- extra_params, rel_source_dirs and rel_include_dirs: as in project_add_contents; function setup_atlas_project(project_name, target_type, rel_source_dirs, rel_include_dirs, extern_libs, extra_params) local source_root = rootdir.."/source/tools/atlas/" .. project_name .. "/" project_create(project_name, target_type) -- if not specified, the default for atlas pch files is in the project root. if not extra_params["pch_dir"] then extra_params["pch_dir"] = source_root end project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) project_add_extern_libs(extern_libs, target_type) -- Platform Specifics if os.istarget("windows") then -- Link to required libraries links { "winmm", "comctl32", "rpcrt4", "delayimp", "ws2_32" } elseif os.istarget("linux") or os.istarget("bsd") then buildoptions { "-rdynamic", "-fPIC" } linkoptions { "-fPIC", "-rdynamic" } -- warnings triggered by wxWidgets buildoptions { "-Wno-unused-local-typedefs" } elseif os.istarget("macosx") then -- install_name settings aren't really supported yet by premake, but there are plans for the future. -- we currently use this hack to work around some bugs with wrong install_names. if target_type == "SharedLib" then if _OPTIONS["macosx-bundle"] then -- If we're building a bundle, it will be in ../Frameworks filter "Debug" linkoptions { "-install_name @executable_path/../Frameworks/lib"..project_name.."_dbg.dylib" } filter "Release" linkoptions { "-install_name @executable_path/../Frameworks/lib"..project_name..".dylib" } filter { } else filter "Debug" linkoptions { "-install_name @executable_path/lib"..project_name.."_dbg.dylib" } filter "Release" linkoptions { "-install_name @executable_path/lib"..project_name..".dylib" } filter { } end end end end -- build all Atlas component projects function setup_atlas_projects() setup_atlas_project("AtlasObject", "StaticLib", { -- src ".", "../../../third_party/jsonspirit" },{ -- include "../../../third_party/jsonspirit" },{ -- extern_libs "boost", "iconv", "libxml2" },{ -- extra_params no_pch = 1 }) atlas_src = { "ActorEditor", "CustomControls/Buttons", "CustomControls/Canvas", "CustomControls/ColorDialog", "CustomControls/DraggableListCtrl", "CustomControls/EditableListCtrl", "CustomControls/FileHistory", "CustomControls/HighResTimer", "CustomControls/MapDialog", "CustomControls/SnapSplitterWindow", "CustomControls/VirtualDirTreeCtrl", "CustomControls/Windows", "General", "General/VideoRecorder", "Misc", "ScenarioEditor", "ScenarioEditor/Sections/Common", "ScenarioEditor/Sections/Cinema", "ScenarioEditor/Sections/Environment", "ScenarioEditor/Sections/Map", "ScenarioEditor/Sections/Object", "ScenarioEditor/Sections/Player", "ScenarioEditor/Sections/Terrain", "ScenarioEditor/Tools", "ScenarioEditor/Tools/Common", } atlas_extra_links = { "AtlasObject" } atlas_extern_libs = { "boost", "comsuppw", "iconv", "libxml2", "sdl", -- key definitions "wxwidgets", "zlib", } if not os.istarget("windows") and not os.istarget("macosx") then -- X11 should only be linked on *nix table.insert(atlas_extern_libs, "x11") end setup_atlas_project("AtlasUI", "SharedLib", atlas_src, { -- include "..", "CustomControls", "Misc" }, atlas_extern_libs, { -- extra_params pch_dir = rootdir.."/source/tools/atlas/AtlasUI/Misc/", no_pch = false, extra_links = atlas_extra_links, extra_files = { "Misc/atlas.rc" } }) end -- Atlas 'frontend' tool-launching projects function setup_atlas_frontend_project (project_name) local target_type = get_main_project_target_type() project_create(project_name, target_type) local source_root = rootdir.."/source/tools/atlas/AtlasFrontends/" files { source_root..project_name..".cpp" } if os.istarget("windows") then files { source_root..project_name..".rc" } end includedirs { source_root .. ".." } -- Platform Specifics if os.istarget("windows") then -- see manifest.cpp project_add_manifest() else -- Non-Windows, = Unix links { "AtlasObject" } end links { "AtlasUI" } end function setup_atlas_frontends() setup_atlas_frontend_project("ActorEditor") end -------------------------------------------------------------------------------- -- collada -------------------------------------------------------------------------------- function setup_collada_project(project_name, target_type, rel_source_dirs, rel_include_dirs, extern_libs, extra_params) project_create(project_name, target_type) local source_root = source_root.."collada/" extra_params["pch_dir"] = source_root project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) project_add_extern_libs(extern_libs, target_type) -- Platform Specifics if os.istarget("windows") then characterset "MBCS" elseif os.istarget("linux") then defines { "LINUX" } links { "dl", } -- FCollada is not aliasing-safe, so disallow dangerous optimisations -- (TODO: It'd be nice to fix FCollada, but that looks hard) buildoptions { "-fno-strict-aliasing" } buildoptions { "-rdynamic" } linkoptions { "-rdynamic" } elseif os.istarget("bsd") then if os.getversion().description == "OpenBSD" then links { "c", } end if os.getversion().description == "GNU/kFreeBSD" then links { "dl", } end buildoptions { "-fno-strict-aliasing" } buildoptions { "-rdynamic" } linkoptions { "-rdynamic" } elseif os.istarget("macosx") then -- define MACOS-something? -- install_name settings aren't really supported yet by premake, but there are plans for the future. -- we currently use this hack to work around some bugs with wrong install_names. if target_type == "SharedLib" then if _OPTIONS["macosx-bundle"] then -- If we're building a bundle, it will be in ../Frameworks linkoptions { "-install_name @executable_path/../Frameworks/lib"..project_name..".dylib" } else linkoptions { "-install_name @executable_path/lib"..project_name..".dylib" } end end buildoptions { "-fno-strict-aliasing" } -- On OSX, fcollada uses a few utility functions from coreservices links { "CoreServices.framework" } end end -- build all Collada component projects function setup_collada_projects() setup_collada_project("Collada", "SharedLib", { -- src "." },{ -- include },{ -- extern_libs "fcollada", "iconv", "libxml2" },{ -- extra_params }) end -------------------------------------------------------------------------------- -- tests -------------------------------------------------------------------------------- function setup_tests() local cxxtest = require "cxxtest" if os.istarget("windows") then cxxtest.setpath(rootdir.."/build/bin/cxxtestgen.exe") else cxxtest.setpath(rootdir.."/libraries/source/cxxtest-4.4/bin/cxxtestgen") end local runner = "ErrorPrinter" if _OPTIONS["jenkins-tests"] then runner = "XmlPrinter" end local includefiles = { -- Precompiled headers - the header is added to all generated .cpp files -- note that the header isn't actually precompiled here, only #included -- so that the build stage can use it as a precompiled header. "precompiled.h", -- This is required to build against SDL 2.0.4 on Windows. "lib/external_libraries/libsdl.h", } cxxtest.init(source_root, true, runner, includefiles) local target_type = get_main_project_target_type() project_create("test", target_type) -- Find header files in 'test' subdirectories local all_files = os.matchfiles(source_root .. "**/tests/*.h") local test_files = {} for i,v in pairs(all_files) do -- Don't include sysdep tests on the wrong sys -- Don't include Atlas tests unless Atlas is being built if not (string.find(v, "/sysdep/os/win/") and not os.istarget("windows")) and not (string.find(v, "/tools/atlas/") and not _OPTIONS["atlas"]) and not (string.find(v, "/sysdep/arch/x86_x64/") and ((arch ~= "amd64") or (arch ~= "x86"))) then table.insert(test_files, v) end end cxxtest.configure_project(test_files) filter "system:not macosx" linkgroups 'On' filter {} links { static_lib_names } filter "Debug" links { static_lib_names_debug } filter "Release" links { static_lib_names_release } filter { } links { "mocks_test" } if _OPTIONS["atlas"] then links { "AtlasObject" } end extra_params = { extra_files = { "test_setup.cpp" }, } project_add_contents(source_root, {}, {}, extra_params) project_add_extern_libs(used_extern_libs, target_type) dependson { "Collada" } -- TODO: should fix the duplication between this OS-specific linking -- code, and the similar version in setup_main_exe if os.istarget("windows") then -- from "lowlevel" static lib; must be added here to be linked in files { source_root.."lib/sysdep/os/win/error_dialog.rc" } rtti "off" -- see wstartup.h linkoptions { "/INCLUDE:_wstartup_InitAndRegisterShutdown" } -- Enables console for the TEST project on Windows linkoptions { "/SUBSYSTEM:CONSOLE" } project_add_manifest() elseif os.istarget("linux") or os.istarget("bsd") then if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then links { "rt" } end if _OPTIONS["android"] then -- NDK's STANDALONE-TOOLCHAIN.html says this is required linkoptions { "-Wl,--fix-cortex-a8" } end if os.istarget("linux") or os.getversion().description == "GNU/kFreeBSD" then links { -- Dynamic libraries (needed for linking for gold) "dl", } elseif os.istarget("bsd") then links { -- Needed for backtrace* on BSDs "execinfo", } end -- Threading support buildoptions { "-pthread" } if not _OPTIONS["android"] then linkoptions { "-pthread" } end -- For debug_resolve_symbol filter "Debug" linkoptions { "-rdynamic" } filter { } includedirs { source_root .. "pch/test/" } elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end -- must come first, so that VC sets it as the default project and therefore -- allows running via F5 without the "where is the EXE" dialog. setup_main_exe() setup_all_libs() -- add the static libs to the main EXE project. only now (after -- setup_all_libs has run) are the lib names known. cannot move -- setup_main_exe to run after setup_all_libs (see comment above). -- we also don't want to hardcode the names - that would require more -- work when changing the static lib breakdown. project("pyrogenesis") -- Set the main project active links { static_lib_names } filter "Debug" links { static_lib_names_debug } filter "Release" links { static_lib_names_release } filter { } if _OPTIONS["atlas"] then setup_atlas_projects() setup_atlas_frontends() end setup_collada_projects() if not _OPTIONS["without-tests"] then setup_tests() end Index: ps/trunk/source/gui/ObjectTypes/CChart.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/CChart.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CChart.h (revision 23028) @@ -0,0 +1,111 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CCHART +#define INCLUDED_CCHART + +#include "graphics/ShaderProgramPtr.h" +#include "gui/ObjectBases/IGUITextOwner.h" +#include "gui/SettingTypes/CGUIColor.h" +#include "gui/SettingTypes/CGUIList.h" +#include "gui/SettingTypes/CGUISeries.h" +#include "maths/Vector2D.h" + +#include + +struct CChartData +{ + // Avoid copying the container. + NONCOPYABLE(CChartData); + MOVABLE(CChartData); + CChartData() = default; + + CGUIColor m_Color; + std::vector m_Points; +}; + +/** + * Chart for a data visualization as lines or points + */ +class CChart : public IGUIObject, public IGUITextOwner +{ + GUI_OBJECT(CChart) + +public: + CChart(CGUI& pGUI); + virtual ~CChart(); + +protected: + /** + * @see IGUIObject#UpdateCachedSize() + */ + void UpdateCachedSize(); + + /** + * @see IGUIObject#HandleMessage() + */ + virtual void HandleMessage(SGUIMessage& Message); + + /** + * Draws the Chart + */ + virtual void Draw(); + + virtual CRect GetChartRect() const; + + void UpdateSeries(); + + void SetupText(); + + std::vector m_Series; + + CVector2D m_LeftBottom, m_RightTop; + + std::vector m_TextPositions; + + bool m_EqualX, m_EqualY; + + // Settings + CGUIColor m_AxisColor; + float m_AxisWidth; + float m_BufferZone; + CStrW m_Font; + CStrW m_FormatX; + CStrW m_FormatY; + CGUIList m_SeriesColor; + CGUISeries m_SeriesSetting; + EAlign m_TextAlign; + +private: + /** + * Helper functions + */ + void DrawLine(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const; + + // Draws the triangle sequence so that the each next triangle has a common edge with the previous one. + // If we need to draw n triangles, we need only n + 2 points. + void DrawTriangleStrip(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const; + + // Represents axes as triangles and draws them with DrawTriangleStrip. + void DrawAxes(const CShaderProgramPtr& shader) const; + + CSize AddFormattedValue(const CStrW& format, const float value, const CStrW& font, const float buffer_zone); + + void UpdateBounds(); +}; + +#endif // INCLUDED_CCHART Property changes on: ps/trunk/source/gui/ObjectTypes/CChart.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CInput.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/CInput.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CInput.h (revision 23028) @@ -0,0 +1,212 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CINPUT +#define INCLUDED_CINPUT + +#include "gui/CGUISprite.h" +#include "gui/ObjectBases/IGUIScrollBarOwner.h" +#include "lib/external_libraries/libsdl.h" + +#include + +/** + * Text field where you can input and edit the text. + * + * It doesn't use IGUITextOwner, because we don't need + * any other features than word-wrapping, and we need to be + * able to rapidly change the string. + */ +class CInput : public IGUIObject, public IGUIScrollBarOwner +{ + GUI_OBJECT(CInput) + +protected: // forwards + struct SRow; + +public: + CInput(CGUI& pGUI); + virtual ~CInput(); + + /** + * @see IGUIObject#ResetStates() + */ + virtual void ResetStates(); + + // Check where the mouse is hovering, and get the appropriate text position. + // return is the text-position index. + int GetMouseHoveringTextPosition() const; + + // Same as above, but only on one row in X, and a given value, not the mouse's. + // wanted is filled with x if the row didn't extend as far as the mouse pos. + int GetXTextPosition(const std::list::const_iterator& c, const float& x, float& wanted) const; + +protected: + /** + * @see IGUIObject#HandleMessage() + */ + virtual void HandleMessage(SGUIMessage& Message); + + /** + * Handle events manually to catch keyboard inputting. + */ + virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev); + + /** + * Handle events manually to catch keys which change the text. + */ + virtual void ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode); + + /** + * Handle events manually to catch keys which don't change the text. + */ + virtual void ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode); + + /** + * Handle hotkey events (called by ManuallyHandleEvent) + */ + virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev); + + /** + * @see IGUIObject#UpdateCachedSize() + */ + virtual void UpdateCachedSize(); + + /** + * Draws the Text + */ + virtual void Draw(); + + /** + * Calculate m_CharacterPosition + * the main task for this function is to perfom word-wrapping + * You input from which character it has been changed, because + * if we add a character to the very last end, we don't want + * process everything all over again! Also notice you can + * specify a 'to' also, it will only be used though if a '\n' + * appears, because then the word-wrapping won't change after + * that. + */ + void UpdateText(int from = 0, int to_before = -1, int to_after = -1); + + /** + * Delete the current selection. Also places the pointer at the + * crack between the two segments kept. + */ + void DeleteCurSelection(); + + /** + * Is text selected? It can be denote two ways, m_iBufferPos_Tail + * being -1 or the same as m_iBufferPos. This makes for clearer + * code. + */ + bool SelectingText() const; + + /// Get area of where text can be drawn. + float GetTextAreaWidth(); + + /// Called every time the auto-scrolling should be checked. + void UpdateAutoScroll(); + + /// Clear composed IME input when supported (SDL2 only). + void ClearComposedText(); + + /// Updates the buffer (cursor) position exposed to JS. + void UpdateBufferPositionSetting(); +protected: + /// Cursor position + int m_iBufferPos; + /// Cursor position we started to select from. (-1 if not selecting) + /// (NB: Can be larger than m_iBufferPos if selecting from back to front.) + int m_iBufferPos_Tail; + + /// If we're composing text with an IME + bool m_ComposingText; + /// The length and position of the current IME composition + int m_iComposedLength, m_iComposedPos; + /// The position to insert committed text + int m_iInsertPos; + + // the outer vector is lines, and the inner is X positions + // in a row. So that we can determine where characters are + // placed. It's important because we need to know where the + // pointer should be placed when the input control is pressed. + struct SRow + { + // Where the Row starts + int m_ListStart; + + // List of X values for each character. + std::vector m_ListOfX; + }; + + /** + * List of rows to ease changing its size, so iterators stay valid. + * For one-liners only one row is used. + */ + std::list m_CharacterPositions; + + // *** Things for a multi-lined input control *** // + + /** + * When you change row with up/down, and the row you jump to does + * not have anything at that X position, then it will keep the + * m_WantedX position in mind when switching to the next row. + * It will keep on being used until it reach a row which meets the + * requirements. + * 0.0f means not in use. + */ + float m_WantedX; + + /** + * If we are in the process of selecting a larger selection of text + * using the mouse click (hold) and drag, this is true. + */ + bool m_SelectingText; + + // *** Things for one-line input control *** // + float m_HorizontalScroll; + + /// Used to store the previous time for flashing the cursor. + double m_PrevTime; + + /// Cursor blink rate in seconds, if greater than 0.0. + double m_CursorBlinkRate; + + /// If the cursor should be drawn or not. + bool m_CursorVisState; + + // Settings + i32 m_BufferPosition; + float m_BufferZone; + CStrW m_Caption; + i32 m_CellID; + CStrW m_Font; + CStrW m_MaskChar; + bool m_Mask; + i32 m_MaxLength; + bool m_MultiLine; + bool m_Readonly; + bool m_ScrollBar; + CStr m_ScrollBarStyle; + CGUISpriteInstance m_Sprite; + CGUISpriteInstance m_SpriteSelectArea; + CGUIColor m_TextColor; + CGUIColor m_TextColorSelected; +}; + +#endif // INCLUDED_CINPUT Property changes on: ps/trunk/source/gui/ObjectTypes/CInput.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CCheckBox.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/CCheckBox.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CCheckBox.h (revision 23028) @@ -0,0 +1,61 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CCHECKBOX +#define INCLUDED_CCHECKBOX + +#include "gui/CGUISprite.h" +#include "gui/ObjectBases/IGUIButtonBehavior.h" + +class CCheckBox : public IGUIObject, public IGUIButtonBehavior +{ + GUI_OBJECT(CCheckBox) + +public: + CCheckBox(CGUI& pGUI); + virtual ~CCheckBox(); + + /** + * @see IGUIObject#ResetStates() + */ + virtual void ResetStates(); + + /** + * @see IGUIObject#HandleMessage() + */ + virtual void HandleMessage(SGUIMessage& Message); + + /** + * Draws the control + */ + virtual void Draw(); + +protected: + // Settings + i32 m_CellID; + bool m_Checked; + CGUISpriteInstance m_SpriteUnchecked; + CGUISpriteInstance m_SpriteUncheckedOver; + CGUISpriteInstance m_SpriteUncheckedPressed; + CGUISpriteInstance m_SpriteUncheckedDisabled; + CGUISpriteInstance m_SpriteChecked; + CGUISpriteInstance m_SpriteCheckedOver; + CGUISpriteInstance m_SpriteCheckedPressed; + CGUISpriteInstance m_SpriteCheckedDisabled; +}; + +#endif // INCLUDED_CCHECKBOX Property changes on: ps/trunk/source/gui/ObjectTypes/CCheckBox.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CDropDown.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/CDropDown.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CDropDown.h (revision 23028) @@ -0,0 +1,142 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +/* +GUI Object - Drop Down (list) + +--Overview-- + + Works just like a list-box, but it hides + all the elements that aren't selected. They + can be brought up by pressing the control. +*/ + +#ifndef INCLUDED_CDROPDOWN +#define INCLUDED_CDROPDOWN + +#include "gui/CGUISprite.h" +#include "gui/ObjectTypes/CList.h" + +#include + +/** + * Drop Down + * + * The control can be pressed, but we will not inherent + * this behavior from IGUIButtonBehavior, because when + * you press this control, the list with elements will + * immediately appear, and not first after release + * (which is the whole gist of the IGUIButtonBehavior). + */ +class CDropDown : public CList +{ + GUI_OBJECT(CDropDown) + +public: + CDropDown(CGUI& pGUI); + virtual ~CDropDown(); + + /** + * @see IGUIObject#HandleMessage() + */ + virtual void HandleMessage(SGUIMessage& Message); + + /** + * Handle events manually to catch keyboard inputting. + */ + virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev); + + /** + * Draws the Button + */ + virtual void Draw(); + + // This is one of the few classes we actually need to redefine this function + // this is because the size of the control changes whether it is open + // or closed. + virtual bool IsMouseOver() const; + + virtual float GetBufferedZ() const; + +protected: + /** + * If the size changed, the texts have to be updated as + * the word wrapping depends on the size. + */ + virtual void UpdateCachedSize(); + + /** + * Sets up text, should be called every time changes has been + * made that can change the visual. + */ + void SetupText(); + + // Sets up the cached GetListRect. Decided whether it should + // have a scrollbar, and so on. + virtual void SetupListRect(); + + // Specify a new List rectangle. + virtual CRect GetListRect() const; + + /** + * Placement of text. + */ + CPos m_TextPos; + + // Is the dropdown opened? + bool m_Open; + + // I didn't cache this at first, but it's just as easy as caching + // m_CachedActualSize, so I thought, what the heck it's used a lot. + CRect m_CachedListRect; + + // Hide scrollbar when it's not needed + bool m_HideScrollBar; + + // Not necessarily the element that is selected, this is just + // which element should be highlighted. When opening the dropdown + // it is set to "selected", but then when moving the mouse it will + // change. + int m_ElementHighlight; + + // Stores any text entered by the user for quick access to an element + // (ie if you type "acro" it will take you to acropolis). + std::string m_InputBuffer; + + // used to know if we want to restart anew or add to m_inputbuffer. + double m_TimeOfLastInput; + + // Settings + float m_ButtonWidth; + float m_DropDownSize; + float m_DropDownBuffer; + u32 m_MinimumVisibleItems; + CStrW m_SoundClosed; + CStrW m_SoundEnter; + CStrW m_SoundLeave; + CStrW m_SoundOpened; + CGUISpriteInstance m_SpriteDisabled; + CGUISpriteInstance m_SpriteList; + CGUISpriteInstance m_Sprite2; + CGUISpriteInstance m_Sprite2Over; + CGUISpriteInstance m_Sprite2Pressed; + CGUISpriteInstance m_Sprite2Disabled; + CGUIColor m_TextColorDisabled; + EVAlign m_TextVAlign; +}; + +#endif // INCLUDED_CDROPDOWN Property changes on: ps/trunk/source/gui/ObjectTypes/CDropDown.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CImage.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CImage.cpp (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CImage.cpp (revision 23028) @@ -0,0 +1,40 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "CImage.h" + +#include "gui/CGUI.h" + +CImage::CImage(CGUI& pGUI) + : IGUIObject(pGUI), + m_Sprite(), + m_CellID() +{ + RegisterSetting("sprite", m_Sprite); + RegisterSetting("cell_id", m_CellID); +} + +CImage::~CImage() +{ +} + +void CImage::Draw() +{ + m_pGUI.DrawSprite(m_Sprite, m_CellID, GetBufferedZ(), m_CachedActualSize); +} Property changes on: ps/trunk/source/gui/ObjectTypes/CImage.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 23028) @@ -0,0 +1,711 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "CMiniMap.h" + +#include "graphics/GameView.h" +#include "graphics/LOSTexture.h" +#include "graphics/MiniPatch.h" +#include "graphics/Terrain.h" +#include "graphics/TerrainTextureEntry.h" +#include "graphics/TerrainTextureManager.h" +#include "graphics/TerritoryTexture.h" +#include "gui/CGUI.h" +#include "gui/GUIManager.h" +#include "gui/GUIMatrix.h" +#include "lib/bits.h" +#include "lib/external_libraries/libsdl.h" +#include "lib/ogl.h" +#include "lib/timer.h" +#include "ps/ConfigDB.h" +#include "ps/Filesystem.h" +#include "ps/Game.h" +#include "ps/GameSetup/Config.h" +#include "ps/Profile.h" +#include "ps/World.h" +#include "ps/XML/Xeromyces.h" +#include "renderer/Renderer.h" +#include "renderer/RenderingOptions.h" +#include "renderer/WaterManager.h" +#include "scriptinterface/ScriptInterface.h" +#include "simulation2/components/ICmpMinimap.h" +#include "simulation2/Simulation2.h" +#include "simulation2/system/ParamNode.h" + +#include + +extern bool g_GameRestarted; + +// Set max drawn entities to UINT16_MAX for now, which is more than enough +// TODO: we should be cleverer about drawing them to reduce clutter +const u16 MAX_ENTITIES_DRAWN = 65535; + +static unsigned int ScaleColor(unsigned int color, float x) +{ + unsigned int r = unsigned(float(color & 0xff) * x); + unsigned int g = unsigned(float((color>>8) & 0xff) * x); + unsigned int b = unsigned(float((color>>16) & 0xff) * x); + return (0xff000000 | b | g<<8 | r<<16); +} + +CMiniMap::CMiniMap(CGUI& pGUI) : + IGUIObject(pGUI), + m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0), m_TerrainDirty(true), m_MapScale(1.f), + m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), + m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), m_WaterHeight(0.0) +{ + m_Clicking = false; + m_MouseHovering = false; + + // Register Relax NG validator + CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); + + // Get the maximum height for unit passage in water. + CParamNode externalParamNode; + CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder"); + const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses"); + if (pathingSettings.GetChild("default").IsOk() && pathingSettings.GetChild("default").GetChild("MaxWaterDepth").IsOk()) + m_ShallowPassageHeight = pathingSettings.GetChild("default").GetChild("MaxWaterDepth").ToFloat(); + else + m_ShallowPassageHeight = 0.0f; + + m_AttributePos.type = GL_FLOAT; + m_AttributePos.elems = 2; + m_VertexArray.AddAttribute(&m_AttributePos); + + m_AttributeColor.type = GL_UNSIGNED_BYTE; + m_AttributeColor.elems = 4; + m_VertexArray.AddAttribute(&m_AttributeColor); + + m_VertexArray.SetNumVertices(MAX_ENTITIES_DRAWN); + m_VertexArray.Layout(); + + m_IndexArray.SetNumVertices(MAX_ENTITIES_DRAWN); + m_IndexArray.Layout(); + VertexArrayIterator index = m_IndexArray.GetIterator(); + for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) + *index++ = i; + m_IndexArray.Upload(); + m_IndexArray.FreeBackingStore(); + + + VertexArrayIterator attrPos = m_AttributePos.GetIterator(); + VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); + for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) + { + (*attrColor)[0] = 0; + (*attrColor)[1] = 0; + (*attrColor)[2] = 0; + (*attrColor)[3] = 0; + ++attrColor; + + (*attrPos)[0] = -10000.0f; + (*attrPos)[1] = -10000.0f; + + ++attrPos; + + } + m_VertexArray.Upload(); + + double blinkDuration = 1.0; + + // Tests won't have config initialised + if (CConfigDB::IsInitialised()) + { + CFG_GET_VAL("gui.session.minimap.pingduration", m_PingDuration); + CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration); + } + m_HalfBlinkDuration = blinkDuration/2; +} + +CMiniMap::~CMiniMap() +{ + Destroy(); +} + +void CMiniMap::HandleMessage(SGUIMessage& Message) +{ + IGUIObject::HandleMessage(Message); + switch (Message.type) + { + case GUIM_MOUSE_PRESS_LEFT: + if (m_MouseHovering) + { + SetCameraPos(); + m_Clicking = true; + } + break; + case GUIM_MOUSE_RELEASE_LEFT: + if (m_MouseHovering && m_Clicking) + SetCameraPos(); + m_Clicking = false; + break; + case GUIM_MOUSE_DBLCLICK_LEFT: + if (m_MouseHovering && m_Clicking) + SetCameraPos(); + m_Clicking = false; + break; + case GUIM_MOUSE_ENTER: + m_MouseHovering = true; + break; + case GUIM_MOUSE_LEAVE: + m_Clicking = false; + m_MouseHovering = false; + break; + case GUIM_MOUSE_RELEASE_RIGHT: + CMiniMap::FireWorldClickEvent(SDL_BUTTON_RIGHT, 1); + break; + case GUIM_MOUSE_DBLCLICK_RIGHT: + CMiniMap::FireWorldClickEvent(SDL_BUTTON_RIGHT, 2); + break; + case GUIM_MOUSE_MOTION: + if (m_MouseHovering && m_Clicking) + SetCameraPos(); + break; + case GUIM_MOUSE_WHEEL_DOWN: + case GUIM_MOUSE_WHEEL_UP: + Message.Skip(); + break; + + default: + break; + } +} + +bool CMiniMap::IsMouseOver() const +{ + // Get the mouse position. + const CPos& mousePos = m_pGUI.GetMousePos(); + // Get the position of the center of the minimap. + CPos minimapCenter = CPos(m_CachedActualSize.left + m_CachedActualSize.GetWidth() / 2.0, m_CachedActualSize.bottom - m_CachedActualSize.GetHeight() / 2.0); + // Take the magnitude of the difference of the mouse position and minimap center. + double distFromCenter = sqrt(pow((mousePos.x - minimapCenter.x), 2) + pow((mousePos.y - minimapCenter.y), 2)); + // If the distance is less then the radius of the minimap (half the width) the mouse is over the minimap. + if (distFromCenter < m_CachedActualSize.GetWidth() / 2.0) + return true; + else + return false; +} + +void CMiniMap::GetMouseWorldCoordinates(float& x, float& z) const +{ + // Determine X and Z according to proportion of mouse position and minimap + + const CPos& mousePos = m_pGUI.GetMousePos(); + + float px = (mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth(); + float py = (m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight(); + + float angle = GetAngle(); + + // Scale world coordinates for shrunken square map + x = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(px-0.5) - sin(angle)*(py-0.5)) + 0.5); + z = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(py-0.5) + sin(angle)*(px-0.5)) + 0.5); +} + +void CMiniMap::SetCameraPos() +{ + CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); + + CVector3D target; + GetMouseWorldCoordinates(target.X, target.Z); + target.Y = terrain->GetExactGroundLevel(target.X, target.Z); + g_Game->GetView()->MoveCameraTarget(target); +} + +float CMiniMap::GetAngle() const +{ + CVector3D cameraIn = m_Camera->m_Orientation.GetIn(); + return -atan2(cameraIn.X, cameraIn.Z); +} + +void CMiniMap::FireWorldClickEvent(int UNUSED(button), int UNUSED(clicks)) +{ + JSContext* cx = g_GUI->GetActiveGUI()->GetScriptInterface()->GetContext(); + JSAutoRequest rq(cx); + + float x, z; + GetMouseWorldCoordinates(x, z); + + JS::RootedValue coords(cx); + ScriptInterface::CreateObject(cx, &coords, "x", x, "z", z); + + JS::AutoValueVector paramData(cx); + paramData.append(coords); + + ScriptEvent("worldclick", paramData); +} + +// This sets up and draws the rectangle on the minimap +// which represents the view of the camera in the world. +void CMiniMap::DrawViewRect(CMatrix3D transform) const +{ + // Compute the camera frustum intersected with a fixed-height plane. + // Use the water height as a fixed base height, which should be the lowest we can go + float h = g_Renderer.GetWaterManager()->m_WaterHeight; + const float width = m_CachedActualSize.GetWidth(); + const float height = m_CachedActualSize.GetHeight(); + const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize); + + CVector3D hitPt[4]; + hitPt[0] = m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h); + hitPt[1] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h); + hitPt[2] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h); + hitPt[3] = m_Camera->GetWorldCoordinates(0, 0, h); + + float ViewRect[4][2]; + for (int i = 0; i < 4; ++i) + { + // convert to minimap space + ViewRect[i][0] = (width * hitPt[i].X * invTileMapSize); + ViewRect[i][1] = (height * hitPt[i].Z * invTileMapSize); + } + + float viewVerts[] = { + ViewRect[0][0], -ViewRect[0][1], + ViewRect[1][0], -ViewRect[1][1], + ViewRect[2][0], -ViewRect[2][1], + ViewRect[3][0], -ViewRect[3][1] + }; + + // Enable Scissoring to restrict the rectangle to only the minimap. + glScissor( + m_CachedActualSize.left * g_GuiScale, + g_Renderer.GetHeight() - m_CachedActualSize.bottom * g_GuiScale, + width * g_GuiScale, + height * g_GuiScale); + glEnable(GL_SCISSOR_TEST); + glLineWidth(2.0f); + + CShaderDefines lineDefines; + lineDefines.Add(str_MINIMAP_LINE, str_1); + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), lineDefines); + tech->BeginPass(); + CShaderProgramPtr shader = tech->GetShader(); + shader->Uniform(str_transform, transform); + shader->Uniform(str_color, 1.0f, 0.3f, 0.3f, 1.0f); + + shader->VertexPointer(2, GL_FLOAT, 0, viewVerts); + shader->AssertPointersBound(); + + if (!g_Renderer.m_SkipSubmit) + glDrawArrays(GL_LINE_LOOP, 0, 4); + + tech->EndPass(); + + glLineWidth(1.0f); + glDisable(GL_SCISSOR_TEST); +} + +struct MinimapUnitVertex +{ + // This struct is copyable for convenience and because to move is to copy for primitives. + u8 r, g, b, a; + float x, y; +}; + +// Adds a vertex to the passed VertexArray +static void inline addVertex(const MinimapUnitVertex& v, + VertexArrayIterator& attrColor, + VertexArrayIterator& attrPos) +{ + (*attrColor)[0] = v.r; + (*attrColor)[1] = v.g; + (*attrColor)[2] = v.b; + (*attrColor)[3] = v.a; + ++attrColor; + + (*attrPos)[0] = v.x; + (*attrPos)[1] = v.y; + + ++attrPos; +} + + +void CMiniMap::DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const +{ + // Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m) + // Scale square maps to fit in circular minimap area + const float s = sin(angle) * m_MapScale; + const float c = cos(angle) * m_MapScale; + const float m = coordMax / 2.f; + + float quadTex[] = { + m*(-c + s + 1.f), m*(-c + -s + 1.f), + m*(c + s + 1.f), m*(-c + s + 1.f), + m*(c + -s + 1.f), m*(c + s + 1.f), + + m*(c + -s + 1.f), m*(c + s + 1.f), + m*(-c + -s + 1.f), m*(c + -s + 1.f), + m*(-c + s + 1.f), m*(-c + -s + 1.f) + }; + float quadVerts[] = { + x, y, z, + x2, y, z, + x2, y2, z, + + x2, y2, z, + x, y2, z, + x, y, z + }; + + shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); + shader->VertexPointer(3, GL_FLOAT, 0, quadVerts); + shader->AssertPointersBound(); + + if (!g_Renderer.m_SkipSubmit) + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +// TODO: render the minimap in a framebuffer and just draw the frambuffer texture +// most of the time, updating the framebuffer twice a frame. +// Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling +// (those operations cause a gpu sync, which slows down the way gpu works) +void CMiniMap::Draw() +{ + PROFILE3("render minimap"); + + // The terrain isn't actually initialized until the map is loaded, which + // happens when the game is started, so abort until then. + if (!g_Game || !g_Game->IsGameStarted()) + return; + + CSimulation2* sim = g_Game->GetSimulation2(); + CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY); + ENSURE(cmpRangeManager); + + // Set our globals in case they hadn't been set before + m_Camera = g_Game->GetView()->GetCamera(); + m_Terrain = g_Game->GetWorld()->GetTerrain(); + m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); + m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); + m_MapSize = m_Terrain->GetVerticesPerSide(); + m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); + m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); + + if (!m_TerrainTexture || g_GameRestarted) + CreateTextures(); + + + // only update 2x / second + // (note: since units only move a few pixels per second on the minimap, + // we can get away with infrequent updates; this is slow) + // TODO: Update all but camera at same speed as simulation + static double last_time; + const double cur_time = timer_Time(); + const bool doUpdate = cur_time - last_time > 0.5; + if (doUpdate) + { + last_time = cur_time; + if (m_TerrainDirty || m_WaterHeight != g_Renderer.GetWaterManager()->m_WaterHeight) + RebuildTerrainTexture(); + } + + const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; + const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; + const float z = GetBufferedZ(); + const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; + const float angle = GetAngle(); + const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); + + // Disable depth updates to prevent apparent z-fighting-related issues + // with some drivers causing units to get drawn behind the texture. + glDepthMask(0); + + CShaderProgramPtr shader; + CShaderTechniquePtr tech; + + CShaderDefines baseDefines; + baseDefines.Add(str_MINIMAP_BASE, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines); + tech->BeginPass(); + shader = tech->GetShader(); + + // Draw the main textured quad + shader->BindTexture(str_baseTex, m_TerrainTexture); + const CMatrix3D baseTransform = GetDefaultGuiMatrix(); + CMatrix3D baseTextureTransform; + baseTextureTransform.SetIdentity(); + shader->Uniform(str_transform, baseTransform); + shader->Uniform(str_textureTransform, baseTextureTransform); + + DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); + + // Draw territory boundaries + glEnable(GL_BLEND); + + CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); + + shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); + const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix(); + shader->Uniform(str_transform, baseTransform); + shader->Uniform(str_textureTransform, *territoryTransform); + + DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); + tech->EndPass(); + + // Draw the LOS quad in black, using alpha values from the LOS texture + CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); + + CShaderDefines losDefines; + losDefines.Add(str_MINIMAP_LOS, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines); + tech->BeginPass(); + shader = tech->GetShader(); + shader->BindTexture(str_baseTex, losTexture.GetTexture()); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix(); + shader->Uniform(str_transform, baseTransform); + shader->Uniform(str_textureTransform, *losTransform); + + DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); + tech->EndPass(); + + glDisable(GL_BLEND); + + PROFILE_START("minimap units"); + + CShaderDefines pointDefines; + pointDefines.Add(str_MINIMAP_POINT, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines); + tech->BeginPass(); + shader = tech->GetShader(); + shader->Uniform(str_transform, baseTransform); + shader->Uniform(str_pointSize, 3.f); + + CMatrix3D unitMatrix; + unitMatrix.SetIdentity(); + // Center the minimap on the origin of the axis of rotation. + unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f); + // Rotate the map. + unitMatrix.RotateZ(angle); + // Scale square maps to fit. + unitMatrix.Scale(unitScale, unitScale, 1.f); + // Move the minimap back to it's starting position. + unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f); + // Move the minimap to it's final location. + unitMatrix.Translate(x, y, z); + // Apply the gui matrix. + unitMatrix *= GetDefaultGuiMatrix(); + // Load the transform into the shader. + shader->Uniform(str_transform, unitMatrix); + + const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); + const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); + + CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); + + if (doUpdate) + { + VertexArrayIterator attrPos = m_AttributePos.GetIterator(); + VertexArrayIterator attrColor = m_AttributeColor.GetIterator(); + + m_EntitiesDrawn = 0; + MinimapUnitVertex v; + std::vector pingingVertices; + pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); + + if (cur_time > m_NextBlinkTime) + { + m_BlinkState = !m_BlinkState; + m_NextBlinkTime = cur_time + m_HalfBlinkDuration; + } + + entity_pos_t posX, posZ; + for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) + { + ICmpMinimap* cmpMinimap = static_cast(it->second); + if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) + { + ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer()); + if (vis != ICmpRangeManager::VIS_HIDDEN) + { + v.a = 255; + v.x = posX.ToFloat() * sx; + v.y = -posZ.ToFloat() * sy; + + // Check minimap pinging to indicate something + if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration)) + { + v.r = 255; // ping color is white + v.g = 255; + v.b = 255; + pingingVertices.push_back(v); + } + else + { + addVertex(v, attrColor, attrPos); + ++m_EntitiesDrawn; + } + } + } + } + + // Add the pinged vertices at the end, so they are drawn on top + for (size_t v = 0; v < pingingVertices.size(); ++v) + { + addVertex(pingingVertices[v], attrColor, attrPos); + ++m_EntitiesDrawn; + } + + ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); + m_VertexArray.Upload(); + } + + m_VertexArray.PrepareForRendering(); + + if (m_EntitiesDrawn > 0) + { +#if !CONFIG2_GLES + if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER) + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + + u8* indexBase = m_IndexArray.Bind(); + u8* base = m_VertexArray.Bind(); + const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); + + shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); + shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); + shader->AssertPointersBound(); + + if (!g_Renderer.m_SkipSubmit) + glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); + + g_Renderer.GetStats().m_DrawCalls++; + CVertexBuffer::Unbind(); + +#if !CONFIG2_GLES + if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER) + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + } + + tech->EndPass(); + + DrawViewRect(unitMatrix); + + PROFILE_END("minimap units"); + + // Reset depth mask + glDepthMask(1); +} + +void CMiniMap::CreateTextures() +{ + Destroy(); + + // Create terrain texture + glGenTextures(1, &m_TerrainTexture); + g_Renderer.BindTexture(0, m_TerrainTexture); + + // Initialise texture with solid black, for the areas we don't + // overwrite with glTexSubImage2D later + u32* texData = new u32[m_TextureSize * m_TextureSize]; + for (ssize_t i = 0; i < m_TextureSize * m_TextureSize; ++i) + texData[i] = 0xFF000000; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); + delete[] texData; + + m_TerrainData = new u32[(m_MapSize - 1) * (m_MapSize - 1)]; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Rebuild and upload both of them + RebuildTerrainTexture(); +} + + +void CMiniMap::RebuildTerrainTexture() +{ + u32 x = 0; + u32 y = 0; + u32 w = m_MapSize - 1; + u32 h = m_MapSize - 1; + m_WaterHeight = g_Renderer.GetWaterManager()->m_WaterHeight; + + m_TerrainDirty = false; + + for (u32 j = 0; j < h; ++j) + { + u32* dataPtr = m_TerrainData + ((y + j) * (m_MapSize - 1)) + x; + for (u32 i = 0; i < w; ++i) + { + float avgHeight = ( m_Terrain->GetVertexGroundLevel((int)i, (int)j) + + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j) + + m_Terrain->GetVertexGroundLevel((int)i, (int)j+1) + + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j+1) + ) / 4.0f; + + if (avgHeight < m_WaterHeight && avgHeight > m_WaterHeight - m_ShallowPassageHeight) + { + // shallow water + *dataPtr++ = 0xffc09870; + } + else if (avgHeight < m_WaterHeight) + { + // Set water as constant color for consistency on different maps + *dataPtr++ = 0xffa07850; + } + else + { + int hmap = ((int)m_Terrain->GetHeightMap()[(y + j) * m_MapSize + x + i]) >> 8; + int val = (hmap / 3) + 170; + + u32 color = 0xFFFFFFFF; + + CMiniPatch* mp = m_Terrain->GetTile(x + i, y + j); + if (mp) + { + CTerrainTextureEntry* tex = mp->GetTextureEntry(); + if (tex) + { + // If the texture can't be loaded yet, set the dirty flags + // so we'll try regenerating the terrain texture again soon + if(!tex->GetTexture()->TryLoad()) + m_TerrainDirty = true; + + color = tex->GetBaseColor(); + } + } + + *dataPtr++ = ScaleColor(color, float(val) / 255.0f); + } + } + } + + // Upload the texture + g_Renderer.BindTexture(0, m_TerrainTexture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize - 1, m_MapSize - 1, GL_RGBA, GL_UNSIGNED_BYTE, m_TerrainData); +} + +void CMiniMap::Destroy() +{ + if (m_TerrainTexture) + { + glDeleteTextures(1, &m_TerrainTexture); + m_TerrainTexture = 0; + } + + SAFE_ARRAY_DELETE(m_TerrainData); +} Property changes on: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/COList.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/COList.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/COList.h (revision 23028) @@ -0,0 +1,91 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ +#ifndef INCLUDED_COLIST +#define INCLUDED_COLIST + +#include "gui/ObjectTypes/CList.h" +#include "gui/SettingTypes/CGUIColor.h" + +#include + +/** + * Represents a column. + */ +struct COListColumn +{ + // Avoid copying the strings. + NONCOPYABLE(COListColumn); + MOVABLE(COListColumn); + COListColumn() : m_Width(0), m_Hidden(false) {} + CGUIColor m_TextColor; + CStr m_Id; + float m_Width; + CStrW m_Heading; // CGUIString?? + CGUIList m_List; + bool m_Hidden; +}; + +/** + * Multi-column list. One row can be selected by the user. + * Individual cells are clipped if the contained text is too long. + * + * The list can be sorted dynamically by JS code when a + * heading is clicked. + * A scroll-bar will appear when needed. + */ +class COList : public CList +{ + GUI_OBJECT(COList) + +public: + COList(CGUI& pGUI); + +protected: + void SetupText(); + void HandleMessage(SGUIMessage& Message); + + /** + * Handle the \ tag. + */ + virtual bool HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile); + virtual void AdditionalChildrenHandled(); + + void DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor); + + virtual CRect GetListRect() const; + + /** + * Available columns. + */ + std::vector m_Columns; + + // Settings + CGUISpriteInstance m_SpriteHeading; + bool m_Sortable; + CStr m_SelectedColumn; + i32 m_SelectedColumnOrder; + CGUISpriteInstance m_SpriteAsc; + CGUISpriteInstance m_SpriteDesc; + CGUISpriteInstance m_SpriteNotSorted; + +private: + // Width of space available for columns + float m_TotalAvailableColumnWidth; + float m_HeadingHeight; +}; + +#endif // INCLUDED_COLIST Property changes on: ps/trunk/source/gui/ObjectTypes/COList.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CInput.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CInput.cpp (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CInput.cpp (revision 23028) @@ -0,0 +1,2051 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "CInput.h" + +#include "graphics/FontMetrics.h" +#include "graphics/ShaderManager.h" +#include "graphics/TextRenderer.h" +#include "gui/CGUI.h" +#include "gui/CGUIScrollBarVertical.h" +#include "lib/sysdep/clipboard.h" +#include "lib/timer.h" +#include "lib/utf8.h" +#include "ps/ConfigDB.h" +#include "ps/GameSetup/Config.h" +#include "ps/Globals.h" +#include "ps/Hotkey.h" +#include "renderer/Renderer.h" + +#include + +extern int g_yres; + +CInput::CInput(CGUI& pGUI) + : + IGUIObject(pGUI), + IGUIScrollBarOwner(*static_cast(this)), + m_iBufferPos(-1), + m_iBufferPos_Tail(-1), + m_SelectingText(), + m_HorizontalScroll(), + m_PrevTime(), + m_CursorVisState(true), + m_CursorBlinkRate(0.5), + m_ComposingText(), + m_iComposedLength(), + m_iComposedPos(), + m_iInsertPos(), + m_BufferPosition(), + m_BufferZone(), + m_Caption(), + m_CellID(), + m_Font(), + m_MaskChar(), + m_Mask(), + m_MaxLength(), + m_MultiLine(), + m_Readonly(), + m_ScrollBar(), + m_ScrollBarStyle(), + m_Sprite(), + m_SpriteSelectArea(), + m_TextColor(), + m_TextColorSelected() +{ + RegisterSetting("buffer_position", m_BufferPosition); + RegisterSetting("buffer_zone", m_BufferZone); + RegisterSetting("caption", m_Caption); + RegisterSetting("cell_id", m_CellID); + RegisterSetting("font", m_Font); + RegisterSetting("mask_char", m_MaskChar); + RegisterSetting("mask", m_Mask); + RegisterSetting("max_length", m_MaxLength); + RegisterSetting("multiline", m_MultiLine); + RegisterSetting("readonly", m_Readonly); + RegisterSetting("scrollbar", m_ScrollBar); + RegisterSetting("scrollbar_style", m_ScrollBarStyle); + RegisterSetting("sprite", m_Sprite); + RegisterSetting("sprite_selectarea", m_SpriteSelectArea); + RegisterSetting("textcolor", m_TextColor); + RegisterSetting("textcolor_selected", m_TextColorSelected); + + CFG_GET_VAL("gui.cursorblinkrate", m_CursorBlinkRate); + + CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI); + bar->SetRightAligned(true); + AddScrollBar(bar); +} + +CInput::~CInput() +{ +} + +void CInput::UpdateBufferPositionSetting() +{ + SetSetting("buffer_position", m_iBufferPos, false); +} + +void CInput::ClearComposedText() +{ + m_Caption.erase(m_iInsertPos, m_iComposedLength); + m_iBufferPos = m_iInsertPos; + UpdateBufferPositionSetting(); + m_iComposedLength = 0; + m_iComposedPos = 0; +} + +InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev) +{ + ENSURE(m_iBufferPos != -1); + + switch (ev->ev.type) + { + case SDL_HOTKEYDOWN: + { + if (m_ComposingText) + return IN_HANDLED; + + return ManuallyHandleHotkeyEvent(ev); + } + // SDL2 has a new method of text input that better supports Unicode and CJK + // see https://wiki.libsdl.org/Tutorials/TextInput + case SDL_TEXTINPUT: + { + if (m_Readonly) + return IN_PASS; + + // Text has been committed, either single key presses or through an IME + std::wstring text = wstring_from_utf8(ev->ev.text.text); + + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + + if (m_ComposingText) + { + ClearComposedText(); + m_ComposingText = false; + } + + if (m_iBufferPos == static_cast(m_Caption.length())) + m_Caption.append(text); + else + m_Caption.insert(m_iBufferPos, text); + + UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); + + m_iBufferPos += text.length(); + UpdateBufferPositionSetting(); + m_iBufferPos_Tail = -1; + + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + + return IN_HANDLED; + } + case SDL_TEXTEDITING: + { + if (m_Readonly) + return IN_PASS; + + // Text is being composed with an IME + // TODO: indicate this by e.g. underlining the uncommitted text + const char* rawText = ev->ev.edit.text; + int rawLength = strlen(rawText); + std::wstring wtext = wstring_from_utf8(rawText); + + debug_printf("SDL_TEXTEDITING: text=%s, start=%d, length=%d\n", rawText, ev->ev.edit.start, ev->ev.edit.length); + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + + // Remember cursor position when text composition begins + if (!m_ComposingText) + m_iInsertPos = m_iBufferPos; + else + { + // Composed text is replaced each time + ClearComposedText(); + } + + m_ComposingText = ev->ev.edit.start != 0 || rawLength != 0; + if (m_ComposingText) + { + m_Caption.insert(m_iInsertPos, wtext); + + // The text buffer is limited to SDL_TEXTEDITINGEVENT_TEXT_SIZE bytes, yet start + // increases without limit, so don't let it advance beyond the composed text length + m_iComposedLength = wtext.length(); + m_iComposedPos = ev->ev.edit.start < m_iComposedLength ? ev->ev.edit.start : m_iComposedLength; + m_iBufferPos = m_iInsertPos + m_iComposedPos; + + // TODO: composed text selection - what does ev.edit.length do? + m_iBufferPos_Tail = -1; + } + + UpdateBufferPositionSetting(); + UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); + + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + + return IN_HANDLED; + } + case SDL_KEYDOWN: + { + if (m_ComposingText) + return IN_HANDLED; + + // Since the GUI framework doesn't handle to set settings + // in Unicode (CStrW), we'll simply retrieve the actual + // pointer and edit that. + SDL_Keycode keyCode = ev->ev.key.keysym.sym; + + ManuallyImmutableHandleKeyDownEvent(keyCode); + ManuallyMutableHandleKeyDownEvent(keyCode); + + UpdateBufferPositionSetting(); + return IN_HANDLED; + } + default: + { + return IN_PASS; + } + } +} + +void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode) +{ + if (m_Readonly) + return; + + wchar_t cooked = 0; + + switch (keyCode) + { + case SDLK_TAB: + { + SendEvent(GUIM_TAB, "tab"); + // Don't send a textedit event, because it should only + // be sent if the GUI control changes the text + break; + } + case SDLK_BACKSPACE: + { + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + else + { + m_iBufferPos_Tail = -1; + + if (m_Caption.empty() || m_iBufferPos == 0) + break; + + if (m_iBufferPos == static_cast(m_Caption.length())) + m_Caption = m_Caption.Left(static_cast(m_Caption.length()) - 1); + else + m_Caption = + m_Caption.Left(m_iBufferPos - 1) + + m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); + + --m_iBufferPos; + + UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos); + } + + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + break; + } + case SDLK_DELETE: + { + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + else + { + if (m_Caption.empty() || m_iBufferPos == static_cast(m_Caption.length())) + break; + + m_Caption = + m_Caption.Left(m_iBufferPos) + + m_Caption.Right(static_cast(m_Caption.length()) - (m_iBufferPos + 1)); + + UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos); + } + + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + break; + } + case SDLK_KP_ENTER: + case SDLK_RETURN: + { + // 'Return' should do a Press event for single liners (e.g. submitting forms) + // otherwise a '\n' character will be added. + if (!m_MultiLine) + { + SendEvent(GUIM_PRESSED, "press"); + break; + } + + cooked = '\n'; // Change to '\n' and do default: + FALLTHROUGH; + } + default: // Insert a character + { + // In SDL2, we no longer get Unicode wchars via SDL_Keysym + // we use text input events instead and they provide UTF-8 chars + if (cooked == 0) + return; + + // check max length + if (m_MaxLength != 0 && static_cast(m_Caption.length()) >= m_MaxLength) + break; + + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + m_iBufferPos_Tail = -1; + + if (m_iBufferPos == static_cast(m_Caption.length())) + m_Caption += cooked; + else + m_Caption = + m_Caption.Left(m_iBufferPos) + cooked + + m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); + + UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos + 1); + + ++m_iBufferPos; + + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + break; + } + } +} + +void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode) +{ + bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]; + + switch (keyCode) + { + case SDLK_HOME: + { + // If there's not a selection, we should create one now + if (!shiftKeyPressed) + { + // Make sure a selection isn't created. + m_iBufferPos_Tail = -1; + } + else if (!SelectingText()) + { + // Place tail at the current point: + m_iBufferPos_Tail = m_iBufferPos; + } + + m_iBufferPos = 0; + m_WantedX = 0.0f; + + UpdateAutoScroll(); + break; + } + case SDLK_END: + { + // If there's not a selection, we should create one now + if (!shiftKeyPressed) + { + // Make sure a selection isn't created. + m_iBufferPos_Tail = -1; + } + else if (!SelectingText()) + { + // Place tail at the current point: + m_iBufferPos_Tail = m_iBufferPos; + } + + m_iBufferPos = static_cast(m_Caption.length()); + m_WantedX = 0.0f; + + UpdateAutoScroll(); + break; + } + /** + * Conventions for Left/Right when text is selected: + * + * References: + * + * Visual Studio + * Visual Studio has the 'newer' approach, used by newer versions of + * things, and in newer applications. A left press will always place + * the pointer on the left edge of the selection, and then of course + * remove the selection. Right will do the exact same thing. + * If you have the pointer on the right edge and press right, it will + * in other words just remove the selection. + * + * Windows (eg. Notepad) + * A left press always takes the pointer a step to the left and + * removes the selection as if it were never there in the first place. + * Right of course does the same thing but to the right. + * + * I chose the Visual Studio convention. Used also in Word, gtk 2.0, MSN + * Messenger. + */ + case SDLK_LEFT: + { + m_WantedX = 0.f; + + if (shiftKeyPressed || !SelectingText()) + { + if (!shiftKeyPressed) + m_iBufferPos_Tail = -1; + else if (!SelectingText()) + m_iBufferPos_Tail = m_iBufferPos; + + if (m_iBufferPos > 0) + --m_iBufferPos; + } + else + { + if (m_iBufferPos_Tail < m_iBufferPos) + m_iBufferPos = m_iBufferPos_Tail; + + m_iBufferPos_Tail = -1; + } + + UpdateAutoScroll(); + break; + } + case SDLK_RIGHT: + { + m_WantedX = 0.0f; + + if (shiftKeyPressed || !SelectingText()) + { + if (!shiftKeyPressed) + m_iBufferPos_Tail = -1; + else if (!SelectingText()) + m_iBufferPos_Tail = m_iBufferPos; + + if (m_iBufferPos < static_cast(m_Caption.length())) + ++m_iBufferPos; + } + else + { + if (m_iBufferPos_Tail > m_iBufferPos) + m_iBufferPos = m_iBufferPos_Tail; + + m_iBufferPos_Tail = -1; + } + + UpdateAutoScroll(); + break; + } + /** + * Conventions for Up/Down when text is selected: + * + * References: + * + * Visual Studio + * Visual Studio has a very strange approach, down takes you below the + * selection to the next row, and up to the one prior to the whole + * selection. The weird part is that it is always aligned as the + * 'pointer'. I decided this is to much work for something that is + * a bit arbitrary + * + * Windows (eg. Notepad) + * Just like with left/right, the selection is destroyed and it moves + * just as if there never were a selection. + * + * I chose the Notepad convention even though I use the VS convention with + * left/right. + */ + case SDLK_UP: + { + if (!shiftKeyPressed) + m_iBufferPos_Tail = -1; + else if (!SelectingText()) + m_iBufferPos_Tail = m_iBufferPos; + + std::list::iterator current = m_CharacterPositions.begin(); + while (current != m_CharacterPositions.end()) + { + if (m_iBufferPos >= current->m_ListStart && + m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size()) + break; + + ++current; + } + + float pos_x; + if (m_iBufferPos - current->m_ListStart == 0) + pos_x = 0.f; + else + pos_x = current->m_ListOfX[m_iBufferPos - current->m_ListStart - 1]; + + if (m_WantedX > pos_x) + pos_x = m_WantedX; + + // Now change row: + if (current != m_CharacterPositions.begin()) + { + --current; + + // Find X-position: + m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX); + } + // else we can't move up + + UpdateAutoScroll(); + break; + } + case SDLK_DOWN: + { + if (!shiftKeyPressed) + m_iBufferPos_Tail = -1; + else if (!SelectingText()) + m_iBufferPos_Tail = m_iBufferPos; + + std::list::iterator current = m_CharacterPositions.begin(); + while (current != m_CharacterPositions.end()) + { + if (m_iBufferPos >= current->m_ListStart && + m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size()) + break; + + ++current; + } + + float pos_x; + + if (m_iBufferPos - current->m_ListStart == 0) + pos_x = 0.f; + else + pos_x = current->m_ListOfX[m_iBufferPos - current->m_ListStart - 1]; + + if (m_WantedX > pos_x) + pos_x = m_WantedX; + + // Now change row: + // Add first, so we can check if it's .end() + ++current; + if (current != m_CharacterPositions.end()) + { + // Find X-position: + m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX); + } + // else we can't move up + + UpdateAutoScroll(); + break; + } + case SDLK_PAGEUP: + { + GetScrollBar(0).ScrollMinusPlenty(); + UpdateAutoScroll(); + break; + } + case SDLK_PAGEDOWN: + { + GetScrollBar(0).ScrollPlusPlenty(); + UpdateAutoScroll(); + break; + } + default: + { + break; + } + } +} + +InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev) +{ + bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]; + + std::string hotkey = static_cast(ev->ev.user.data1); + + if (hotkey == "paste") + { + if (m_Readonly) + return IN_PASS; + + m_WantedX = 0.0f; + + wchar_t* text = sys_clipboard_get(); + if (text) + { + if (SelectingText()) + DeleteCurSelection(); + + if (m_iBufferPos == static_cast(m_Caption.length())) + m_Caption += text; + else + m_Caption = + m_Caption.Left(m_iBufferPos) + text + + m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); + + UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); + + m_iBufferPos += (int)wcslen(text); + UpdateAutoScroll(); + UpdateBufferPositionSetting(); + + sys_clipboard_free(text); + + SendEvent(GUIM_TEXTEDIT, "textedit"); + } + + return IN_HANDLED; + } + else if (hotkey == "copy" || hotkey == "cut") + { + if (m_Readonly && hotkey == "cut") + return IN_PASS; + + m_WantedX = 0.0f; + + if (SelectingText()) + { + int virtualFrom; + int virtualTo; + + if (m_iBufferPos_Tail >= m_iBufferPos) + { + virtualFrom = m_iBufferPos; + virtualTo = m_iBufferPos_Tail; + } + else + { + virtualFrom = m_iBufferPos_Tail; + virtualTo = m_iBufferPos; + } + + CStrW text = m_Caption.Left(virtualTo).Right(virtualTo - virtualFrom); + + sys_clipboard_set(&text[0]); + + if (hotkey == "cut") + { + DeleteCurSelection(); + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + } + } + + return IN_HANDLED; + } + else if (hotkey == "text.delete.left") + { + if (m_Readonly) + return IN_PASS; + + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + + if (!m_Caption.empty() && m_iBufferPos != 0) + { + m_iBufferPos_Tail = m_iBufferPos; + CStrW searchString = m_Caption.Left(m_iBufferPos); + + // If we are starting in whitespace, adjust position until we get a non whitespace + while (m_iBufferPos > 0) + { + if (!iswspace(searchString[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + } + + // If we end up on a punctuation char we just delete it (treat punct like a word) + if (iswpunct(searchString[m_iBufferPos - 1])) + m_iBufferPos--; + else + { + // Now we are on a non white space character, adjust position to char after next whitespace char is found + while (m_iBufferPos > 0) + { + if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + } + } + + UpdateBufferPositionSetting(); + DeleteCurSelection(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + } + UpdateAutoScroll(); + return IN_HANDLED; + } + else if (hotkey == "text.delete.right") + { + if (m_Readonly) + return IN_PASS; + + m_WantedX = 0.0f; + + if (SelectingText()) + DeleteCurSelection(); + + if (!m_Caption.empty() && m_iBufferPos < static_cast(m_Caption.length())) + { + // Delete the word to the right of the cursor + m_iBufferPos_Tail = m_iBufferPos; + + // Delete chars to the right unit we hit whitespace + while (++m_iBufferPos < static_cast(m_Caption.length())) + { + if (iswspace(m_Caption[m_iBufferPos]) || iswpunct(m_Caption[m_iBufferPos])) + break; + } + + // Eliminate any whitespace behind the word we just deleted + while (m_iBufferPos < static_cast(m_Caption.length())) + { + if (!iswspace(m_Caption[m_iBufferPos])) + break; + + ++m_iBufferPos; + } + UpdateBufferPositionSetting(); + DeleteCurSelection(); + } + UpdateAutoScroll(); + SendEvent(GUIM_TEXTEDIT, "textedit"); + return IN_HANDLED; + } + else if (hotkey == "text.move.left") + { + m_WantedX = 0.0f; + + if (shiftKeyPressed || !SelectingText()) + { + if (!shiftKeyPressed) + m_iBufferPos_Tail = -1; + else if (!SelectingText()) + m_iBufferPos_Tail = m_iBufferPos; + + if (!m_Caption.empty() && m_iBufferPos != 0) + { + CStrW searchString = m_Caption.Left(m_iBufferPos); + + // If we are starting in whitespace, adjust position until we get a non whitespace + while (m_iBufferPos > 0) + { + if (!iswspace(searchString[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + } + + // If we end up on a puctuation char we just select it (treat punct like a word) + if (iswpunct(searchString[m_iBufferPos - 1])) + m_iBufferPos--; + else + { + // Now we are on a non white space character, adjust position to char after next whitespace char is found + while (m_iBufferPos > 0) + { + if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + } + } + } + } + else + { + if (m_iBufferPos_Tail < m_iBufferPos) + m_iBufferPos = m_iBufferPos_Tail; + + m_iBufferPos_Tail = -1; + } + + UpdateBufferPositionSetting(); + UpdateAutoScroll(); + + return IN_HANDLED; + } + else if (hotkey == "text.move.right") + { + m_WantedX = 0.0f; + + if (shiftKeyPressed || !SelectingText()) + { + if (!shiftKeyPressed) + m_iBufferPos_Tail = -1; + else if (!SelectingText()) + m_iBufferPos_Tail = m_iBufferPos; + + if (!m_Caption.empty() && m_iBufferPos < static_cast(m_Caption.length())) + { + // Select chars to the right until we hit whitespace + while (++m_iBufferPos < static_cast(m_Caption.length())) + { + if (iswspace(m_Caption[m_iBufferPos]) || iswpunct(m_Caption[m_iBufferPos])) + break; + } + + // Also select any whitespace following the word we just selected + while (m_iBufferPos < static_cast(m_Caption.length())) + { + if (!iswspace(m_Caption[m_iBufferPos])) + break; + + ++m_iBufferPos; + } + } + } + else + { + if (m_iBufferPos_Tail > m_iBufferPos) + m_iBufferPos = m_iBufferPos_Tail; + + m_iBufferPos_Tail = -1; + } + + UpdateBufferPositionSetting(); + UpdateAutoScroll(); + + return IN_HANDLED; + } + + return IN_PASS; +} + +void CInput::ResetStates() +{ + IGUIObject::ResetStates(); + IGUIScrollBarOwner::ResetStates(); +} + +void CInput::HandleMessage(SGUIMessage& Message) +{ + IGUIObject::HandleMessage(Message); + IGUIScrollBarOwner::HandleMessage(Message); + + switch (Message.type) + { + case GUIM_SETTINGS_UPDATED: + { + // Update scroll-bar + // TODO Gee: (2004-09-01) Is this really updated each time it should? + if (m_ScrollBar && + (Message.value == "size" || + Message.value == "z" || + Message.value == "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 == "scrollbar_style") + GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); + + if (Message.value == "buffer_position") + { + m_iBufferPos = m_BufferPosition; + m_iBufferPos_Tail = -1; // position change resets selection + } + + if (Message.value == "size" || + Message.value == "z" || + Message.value == "font" || + Message.value == "absolute" || + Message.value == "caption" || + Message.value == "scrollbar" || + Message.value == "scrollbar_style") + { + UpdateText(); + } + + if (Message.value == "multiline") + { + if (!m_MultiLine) + GetScrollBar(0).SetLength(0.f); + else + GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + + UpdateText(); + } + + UpdateAutoScroll(); + + break; + } + case GUIM_MOUSE_PRESS_LEFT: + { + // Check if we're selecting the scrollbar + if (m_ScrollBar && + m_MultiLine && + GetScrollBar(0).GetStyle()) + { + if (m_pGUI.GetMousePos().x > m_CachedActualSize.right - GetScrollBar(0).GetStyle()->m_Width) + break; + } + + if (m_ComposingText) + break; + + // Okay, this section is about pressing the mouse and + // choosing where the point should be placed. For + // instance, if we press between a and b, the point + // should of course be placed accordingly. Other + // special cases are handled like the input box norms. + if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]) + m_iBufferPos = GetMouseHoveringTextPosition(); + else + m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition(); + + m_SelectingText = true; + + UpdateAutoScroll(); + + // If we immediately release the button it will just be seen as a click + // for the user though. + break; + } + case GUIM_MOUSE_DBLCLICK_LEFT: + { + if (m_ComposingText) + break; + + if (m_Caption.empty()) + break; + + m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition(); + + if (m_iBufferPos >= (int)m_Caption.length()) + m_iBufferPos = m_iBufferPos_Tail = m_Caption.length() - 1; + + // See if we are clicking over whitespace + if (iswspace(m_Caption[m_iBufferPos])) + { + // see if we are in a section of whitespace greater than one character + if ((m_iBufferPos + 1 < (int) m_Caption.length() && iswspace(m_Caption[m_iBufferPos + 1])) || + (m_iBufferPos - 1 > 0 && iswspace(m_Caption[m_iBufferPos - 1]))) + { + // + // We are clicking in an area with more than one whitespace character + // so we select both the word to the left and then the word to the right + // + // [1] First the left + // skip the whitespace + while (m_iBufferPos > 0) + { + if (!iswspace(m_Caption[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + } + // now go until we hit white space or punctuation + while (m_iBufferPos > 0) + { + if (iswspace(m_Caption[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + + if (iswpunct(m_Caption[m_iBufferPos])) + break; + } + + // [2] Then the right + // go right until we are not in whitespace + while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) + { + if (!iswspace(m_Caption[m_iBufferPos_Tail])) + break; + } + + if (m_iBufferPos_Tail == static_cast(m_Caption.length())) + break; + + // now go to the right until we hit whitespace or punctuation + while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) + { + if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) + break; + } + } + else + { + // single whitespace so select word to the right + while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) + { + if (!iswspace(m_Caption[m_iBufferPos_Tail])) + break; + } + + if (m_iBufferPos_Tail == static_cast(m_Caption.length())) + break; + + // Don't include the leading whitespace + m_iBufferPos = m_iBufferPos_Tail; + + // now go to the right until we hit whitespace or punctuation + while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) + { + if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) + break; + } + } + } + else + { + // clicked on non-whitespace so select current word + // go until we hit white space or punctuation + while (m_iBufferPos > 0) + { + if (iswspace(m_Caption[m_iBufferPos - 1])) + break; + + m_iBufferPos--; + + if (iswpunct(m_Caption[m_iBufferPos])) + break; + } + // go to the right until we hit whitespace or punctuation + while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) + if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) + break; + } + UpdateAutoScroll(); + break; + } + case GUIM_MOUSE_RELEASE_LEFT: + { + if (m_SelectingText) + m_SelectingText = false; + break; + } + case GUIM_MOUSE_MOTION: + { + // If we just pressed down and started to move before releasing + // this is one way of selecting larger portions of text. + if (m_SelectingText) + { + // Actually, first we need to re-check that the mouse button is + // really pressed (it can be released while outside the control. + if (!g_mouse_buttons[SDL_BUTTON_LEFT]) + m_SelectingText = false; + else + m_iBufferPos = GetMouseHoveringTextPosition(); + UpdateAutoScroll(); + } + break; + } + case GUIM_LOAD: + { + 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); + GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); + + UpdateText(); + UpdateAutoScroll(); + + break; + } + case GUIM_GOT_FOCUS: + { + m_iBufferPos = 0; + m_PrevTime = 0.0; + m_CursorVisState = false; + + // Tell the IME where to draw the candidate list + SDL_Rect rect; + rect.h = m_CachedActualSize.GetSize().cy; + rect.w = m_CachedActualSize.GetSize().cx; + rect.x = m_CachedActualSize.TopLeft().x; + rect.y = m_CachedActualSize.TopLeft().y; + SDL_SetTextInputRect(&rect); + SDL_StartTextInput(); + break; + } + case GUIM_LOST_FOCUS: + { + if (m_ComposingText) + { + // Simulate a final text editing event to clear the composition + SDL_Event_ evt; + evt.ev.type = SDL_TEXTEDITING; + evt.ev.edit.length = 0; + evt.ev.edit.start = 0; + evt.ev.edit.text[0] = 0; + ManuallyHandleEvent(&evt); + } + SDL_StopTextInput(); + + m_iBufferPos = -1; + m_iBufferPos_Tail = -1; + break; + } + default: + { + break; + } + } + UpdateBufferPositionSetting(); +} + +void CInput::UpdateCachedSize() +{ + // If an ancestor's size changed, this will let us intercept the change and + // update our scrollbar positions + + IGUIObject::UpdateCachedSize(); + + if (m_ScrollBar) + { + 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); + } +} + +void CInput::Draw() +{ + float bz = GetBufferedZ(); + + if (m_CursorBlinkRate > 0.0) + { + // check if the cursor visibility state needs to be changed + double currTime = timer_Time(); + if (currTime - m_PrevTime >= m_CursorBlinkRate) + { + m_CursorVisState = !m_CursorVisState; + m_PrevTime = currTime; + } + } + else + // should always be visible + m_CursorVisState = true; + + // First call draw on ScrollBarOwner + if (m_ScrollBar && m_MultiLine) + IGUIScrollBarOwner::Draw(); + + CStrIntern font_name(m_Font.ToUTF8()); + + wchar_t mask_char = L'*'; + if (m_Mask && m_MaskChar.length() > 0) + mask_char = m_MaskChar[0]; + + m_pGUI.DrawSprite(m_Sprite, m_CellID, bz, m_CachedActualSize); + + float scroll = 0.f; + if (m_ScrollBar && m_MultiLine) + scroll = GetScrollBar(0).GetPos(); + + CFontMetrics font(font_name); + + // We'll have to setup clipping manually, since we're doing the rendering manually. + CRect cliparea(m_CachedActualSize); + + // First we'll figure out the clipping area, which is the cached actual size + // substracted by an optional scrollbar + if (m_ScrollBar) + { + scroll = GetScrollBar(0).GetPos(); + + // substract scrollbar from cliparea + if (cliparea.right > GetScrollBar(0).GetOuterRect().left && + cliparea.right <= GetScrollBar(0).GetOuterRect().right) + cliparea.right = GetScrollBar(0).GetOuterRect().left; + + if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && + cliparea.left < GetScrollBar(0).GetOuterRect().right) + cliparea.left = GetScrollBar(0).GetOuterRect().right; + } + + if (cliparea != CRect()) + { + glEnable(GL_SCISSOR_TEST); + glScissor( + cliparea.left * g_GuiScale, + g_yres - cliparea.bottom * g_GuiScale, + cliparea.GetWidth() * g_GuiScale, + cliparea.GetHeight() * g_GuiScale); + } + + // These are useful later. + int VirtualFrom, VirtualTo; + + if (m_iBufferPos_Tail >= m_iBufferPos) + { + VirtualFrom = m_iBufferPos; + VirtualTo = m_iBufferPos_Tail; + } + else + { + VirtualFrom = m_iBufferPos_Tail; + VirtualTo = m_iBufferPos; + } + + // Get the height of this font. + float h = (float)font.GetHeight(); + float ls = (float)font.GetLineSpacing(); + + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); + + CTextRenderer textRenderer(tech->GetShader()); + textRenderer.Font(font_name); + + // Set the Z to somewhat more, so we can draw a selected area between the + // the control and the text. + textRenderer.Translate( + (float)(int)(m_CachedActualSize.left) + m_BufferZone, + (float)(int)(m_CachedActualSize.top+h) + m_BufferZone, + bz+0.1f); + + // U+FE33: PRESENTATION FORM FOR VERTICAL LOW LINE + // (sort of like a | which is aligned to the left of most characters) + + float buffered_y = -scroll + m_BufferZone; + + // When selecting larger areas, we need to draw a rectangle box + // around it, and this is to keep track of where the box + // started, because we need to follow the iteration until we + // reach the end, before we can actually draw it. + bool drawing_box = false; + float box_x = 0.f; + + float x_pointer = 0.f; + + // If we have a selecting box (i.e. when you have selected letters, not just when + // the pointer is between two letters) we need to process all letters once + // before we do it the second time and render all the text. We can't do it + // in the same loop because text will have been drawn, so it will disappear when + // drawn behind the text that has already been drawn. Confusing, well it's necessary + // (I think). + + if (SelectingText()) + { + // Now m_iBufferPos_Tail can be of both sides of m_iBufferPos, + // just like you can select from right to left, as you can + // left to right. Is there a difference? Yes, the pointer + // be placed accordingly, so that if you select shift and + // expand this selection, it will expand on appropriate side. + // Anyway, since the drawing procedure needs "To" to be + // greater than from, we need virtual values that might switch + // place. + + int VirtualFrom, VirtualTo; + + if (m_iBufferPos_Tail >= m_iBufferPos) + { + VirtualFrom = m_iBufferPos; + VirtualTo = m_iBufferPos_Tail; + } + else + { + VirtualFrom = m_iBufferPos_Tail; + VirtualTo = m_iBufferPos; + } + + + bool done = false; + for (std::list::const_iterator it = m_CharacterPositions.begin(); + it != m_CharacterPositions.end(); + ++it, buffered_y += ls, x_pointer = 0.f) + { + if (m_MultiLine && buffered_y > m_CachedActualSize.GetHeight()) + break; + + // We might as well use 'i' here to iterate, because we need it + // (often compared against ints, so don't make it size_t) + for (int i = 0; i < (int)it->m_ListOfX.size()+2; ++i) + { + if (it->m_ListStart + i == VirtualFrom) + { + // we won't actually draw it now, because we don't + // know the width of each glyph to that position. + // we need to go along with the iteration, and + // make a mark where the box started: + drawing_box = true; // will turn false when finally rendered. + + // Get current x position + box_x = x_pointer; + } + + const bool at_end = (i == (int)it->m_ListOfX.size()+1); + + if (drawing_box && (it->m_ListStart + i == VirtualTo || at_end)) + { + // Depending on if it's just a row change, or if it's + // the end of the select box, do slightly different things. + if (at_end) + { + if (it->m_ListStart + i != VirtualFrom) + // and actually add a white space! yes, this is done in any common input + x_pointer += font.GetCharacterWidth(L' '); + } + else + { + drawing_box = false; + done = true; + } + + CRect rect; + // Set 'rect' depending on if it's a multiline control, or a one-line control + if (m_MultiLine) + { + rect = CRect( + m_CachedActualSize.left + box_x + m_BufferZone, + m_CachedActualSize.top + buffered_y + (h - ls) / 2, + m_CachedActualSize.left + x_pointer + m_BufferZone, + m_CachedActualSize.top + buffered_y + (h + ls) / 2); + + if (rect.bottom < m_CachedActualSize.top) + continue; + + if (rect.top < m_CachedActualSize.top) + rect.top = m_CachedActualSize.top; + + if (rect.bottom > m_CachedActualSize.bottom) + rect.bottom = m_CachedActualSize.bottom; + } + else // if one-line + { + rect = CRect( + m_CachedActualSize.left + box_x + m_BufferZone - m_HorizontalScroll, + m_CachedActualSize.top + buffered_y + (h - ls) / 2, + m_CachedActualSize.left + x_pointer + m_BufferZone - m_HorizontalScroll, + m_CachedActualSize.top + buffered_y + (h + ls) / 2); + + if (rect.left < m_CachedActualSize.left) + rect.left = m_CachedActualSize.left; + + if (rect.right > m_CachedActualSize.right) + rect.right = m_CachedActualSize.right; + } + + m_pGUI.DrawSprite(m_SpriteSelectArea, m_CellID, bz + 0.05f, rect); + } + + if (i < (int)it->m_ListOfX.size()) + { + if (!m_Mask) + x_pointer += font.GetCharacterWidth(m_Caption[it->m_ListStart + i]); + else + x_pointer += font.GetCharacterWidth(mask_char); + } + } + + if (done) + break; + + // If we're about to draw a box, and all of a sudden changes + // line, we need to draw that line's box, and then reset + // the box drawing to the beginning of the new line. + if (drawing_box) + box_x = 0.f; + } + } + + // Reset some from previous run + buffered_y = -scroll; + + // Setup initial color (then it might change and change back, when drawing selected area) + textRenderer.Color(m_TextColor); + + tech->BeginPass(); + + bool using_selected_color = false; + + for (std::list::const_iterator it = m_CharacterPositions.begin(); + it != m_CharacterPositions.end(); + ++it, buffered_y += ls) + { + if (buffered_y + m_BufferZone >= -ls || !m_MultiLine) + { + if (m_MultiLine && buffered_y + m_BufferZone > m_CachedActualSize.GetHeight()) + break; + + CMatrix3D savedTransform = textRenderer.GetTransform(); + + // Text must always be drawn in integer values. So we have to convert scroll + if (m_MultiLine) + textRenderer.Translate(0.f, -(float)(int)scroll, 0.f); + else + textRenderer.Translate(-(float)(int)m_HorizontalScroll, 0.f, 0.f); + + // We might as well use 'i' here, because we need it + // (often compared against ints, so don't make it size_t) + for (int i = 0; i < (int)it->m_ListOfX.size()+1; ++i) + { + if (!m_MultiLine && i < (int)it->m_ListOfX.size()) + { + if (it->m_ListOfX[i] - m_HorizontalScroll < -m_BufferZone) + { + // We still need to translate the OpenGL matrix + if (i == 0) + textRenderer.Translate(it->m_ListOfX[i], 0.f, 0.f); + else + textRenderer.Translate(it->m_ListOfX[i] - it->m_ListOfX[i-1], 0.f, 0.f); + + continue; + } + } + + // End of selected area, change back color + if (SelectingText() && it->m_ListStart + i == VirtualTo) + { + using_selected_color = false; + textRenderer.Color(m_TextColor); + } + + // selecting only one, then we need only to draw a cursor. + if (i != (int)it->m_ListOfX.size() && it->m_ListStart + i == m_iBufferPos && m_CursorVisState) + textRenderer.Put(0.0f, 0.0f, L"_"); + + // Drawing selected area + if (SelectingText() && + it->m_ListStart + i >= VirtualFrom && + it->m_ListStart + i < VirtualTo && + !using_selected_color) + { + using_selected_color = true; + textRenderer.Color(m_TextColorSelected); + } + + if (i != (int)it->m_ListOfX.size()) + { + if (!m_Mask) + textRenderer.PrintfAdvance(L"%lc", m_Caption[it->m_ListStart + i]); + else + textRenderer.PrintfAdvance(L"%lc", mask_char); + } + + // check it's now outside a one-liner, then we'll break + if (!m_MultiLine && i < (int)it->m_ListOfX.size() && + it->m_ListOfX[i] - m_HorizontalScroll > m_CachedActualSize.GetWidth() - m_BufferZone) + break; + } + + if (it->m_ListStart + (int)it->m_ListOfX.size() == m_iBufferPos) + { + textRenderer.Color(m_TextColor); + if (m_CursorVisState) + textRenderer.PutAdvance(L"_"); + + if (using_selected_color) + textRenderer.Color(m_TextColorSelected); + } + + textRenderer.SetTransform(savedTransform); + } + + textRenderer.Translate(0.f, ls, 0.f); + } + + textRenderer.Render(); + + if (cliparea != CRect()) + glDisable(GL_SCISSOR_TEST); + + tech->EndPass(); +} + +void CInput::UpdateText(int from, int to_before, int to_after) +{ + CStrIntern font_name(m_Font.ToUTF8()); + + wchar_t mask_char = L'*'; + if (m_Mask && m_MaskChar.length() > 0) + mask_char = m_MaskChar[0]; + + // Ensure positions are valid after caption changes + m_iBufferPos = std::min(m_iBufferPos, static_cast(m_Caption.size())); + m_iBufferPos_Tail = std::min(m_iBufferPos_Tail, static_cast(m_Caption.size())); + UpdateBufferPositionSetting(); + + if (font_name.empty()) + { + // Destroy everything stored, there's no font, so there can be no data. + m_CharacterPositions.clear(); + return; + } + + SRow row; + row.m_ListStart = 0; + + int to = 0; // make sure it's initialized + + if (to_before == -1) + to = static_cast(m_Caption.length()); + + CFontMetrics font(font_name); + + std::list::iterator current_line; + + // Used to ... TODO + int check_point_row_start = -1; + int check_point_row_end = -1; + + // Reset + if (from == 0 && to_before == -1) + { + m_CharacterPositions.clear(); + current_line = m_CharacterPositions.begin(); + } + else + { + ENSURE(to_before != -1); + + std::list::iterator destroy_row_from; + std::list::iterator destroy_row_to; + // Used to check if the above has been set to anything, + // previously a comparison like: + // destroy_row_from == std::list::iterator() + // ... was used, but it didn't work with GCC. + bool destroy_row_from_used = false; + bool destroy_row_to_used = false; + + // Iterate, and remove everything between 'from' and 'to_before' + // actually remove the entire lines they are on, it'll all have + // to be redone. And when going along, we'll delete a row at a time + // when continuing to see how much more after 'to' we need to remake. + int i = 0; + for (std::list::iterator it = m_CharacterPositions.begin(); + it != m_CharacterPositions.end(); + ++it, ++i) + { + if (!destroy_row_from_used && it->m_ListStart > from) + { + // Destroy the previous line, and all to 'to_before' + destroy_row_from = it; + --destroy_row_from; + + destroy_row_from_used = true; + + // For the rare case that we might remove characters to a word + // so that it suddenly fits on the previous row, + // we need to by standards re-do the whole previous line too + // (if one exists) + if (destroy_row_from != m_CharacterPositions.begin()) + --destroy_row_from; + } + + if (!destroy_row_to_used && it->m_ListStart > to_before) + { + destroy_row_to = it; + destroy_row_to_used = true; + + // If it isn't the last row, we'll add another row to delete, + // just so we can see if the last restorted line is + // identical to what it was before. If it isn't, then we'll + // have to continue. + // 'check_point_row_start' is where we store how the that + // line looked. + if (destroy_row_to != m_CharacterPositions.end()) + { + check_point_row_start = destroy_row_to->m_ListStart; + check_point_row_end = check_point_row_start + (int)destroy_row_to->m_ListOfX.size(); + if (destroy_row_to->m_ListOfX.empty()) + ++check_point_row_end; + } + + ++destroy_row_to; + break; + } + } + + if (!destroy_row_from_used) + { + destroy_row_from = m_CharacterPositions.end(); + --destroy_row_from; + + // As usual, let's destroy another row back + if (destroy_row_from != m_CharacterPositions.begin()) + --destroy_row_from; + + current_line = destroy_row_from; + } + + if (!destroy_row_to_used) + { + destroy_row_to = m_CharacterPositions.end(); + check_point_row_start = -1; + } + + // set 'from' to the row we'll destroy from + // and 'to' to the row we'll destroy to + from = destroy_row_from->m_ListStart; + + if (destroy_row_to != m_CharacterPositions.end()) + to = destroy_row_to->m_ListStart; // notice it will iterate [from, to), so it will never reach to. + else + to = static_cast(m_Caption.length()); + + + // Setup the first row + row.m_ListStart = destroy_row_from->m_ListStart; + + std::list::iterator temp_it = destroy_row_to; + --temp_it; + + current_line = m_CharacterPositions.erase(destroy_row_from, destroy_row_to); + + // If there has been a change in number of characters + // we need to change all m_ListStart that comes after + // the interval we just destroyed. We'll change all + // values with the delta change of the string length. + int delta = to_after - to_before; + if (delta != 0) + { + for (std::list::iterator it = current_line; + it != m_CharacterPositions.end(); + ++it) + it->m_ListStart += delta; + + // Update our check point too! + check_point_row_start += delta; + check_point_row_end += delta; + + if (to != static_cast(m_Caption.length())) + to += delta; + } + } + + int last_word_started = from; + float x_pos = 0.f; + + //if (to_before != -1) + // return; + + for (int i = from; i < to; ++i) + { + if (m_Caption[i] == L'\n' && m_MultiLine) + { + if (i == to-1 && to != static_cast(m_Caption.length())) + break; // it will be added outside + + current_line = m_CharacterPositions.insert(current_line, row); + ++current_line; + + // Setup the next row: + row.m_ListOfX.clear(); + row.m_ListStart = i+1; + x_pos = 0.f; + } + else + { + if (m_Caption[i] == L' '/* || TODO Gee (2004-10-13): the '-' disappears, fix. + m_Caption[i] == L'-'*/) + last_word_started = i+1; + + if (!m_Mask) + x_pos += font.GetCharacterWidth(m_Caption[i]); + else + x_pos += font.GetCharacterWidth(mask_char); + + if (x_pos >= GetTextAreaWidth() && m_MultiLine) + { + // The following decides whether it will word-wrap a word, + // or if it's only one word on the line, where it has to + // break the word apart. + if (last_word_started == row.m_ListStart) + { + last_word_started = i; + row.m_ListOfX.resize(row.m_ListOfX.size() - (i-last_word_started)); + //row.m_ListOfX.push_back(x_pos); + //continue; + } + else + { + // regular word-wrap + row.m_ListOfX.resize(row.m_ListOfX.size() - (i-last_word_started+1)); + } + + // Now, create a new line: + // notice: when we enter a newline, you can stand with the cursor + // both before and after that character, being on different + // rows. With automatic word-wrapping, that is not possible. Which + // is intuitively correct. + + current_line = m_CharacterPositions.insert(current_line, row); + ++current_line; + + // Setup the next row: + row.m_ListOfX.clear(); + row.m_ListStart = last_word_started; + + i = last_word_started-1; + + x_pos = 0.f; + } + else + // Get width of this character: + row.m_ListOfX.push_back(x_pos); + } + + // Check if it's the last iteration, and we're not revising the whole string + // because in that case, more word-wrapping might be needed. + // also check if the current line isn't the end + if (to_before != -1 && i == to-1 && current_line != m_CharacterPositions.end()) + { + // check all rows and see if any existing + if (row.m_ListStart != check_point_row_start) + { + std::list::iterator destroy_row_from; + std::list::iterator destroy_row_to; + // Are used to check if the above has been set to anything, + // previously a comparison like: + // destroy_row_from == std::list::iterator() + // was used, but it didn't work with GCC. + bool destroy_row_from_used = false; + bool destroy_row_to_used = false; + + // Iterate, and remove everything between 'from' and 'to_before' + // actually remove the entire lines they are on, it'll all have + // to be redone. And when going along, we'll delete a row at a time + // when continuing to see how much more after 'to' we need to remake. + int i = 0; + for (std::list::iterator it = m_CharacterPositions.begin(); + it != m_CharacterPositions.end(); + ++it, ++i) + { + if (!destroy_row_from_used && it->m_ListStart > check_point_row_start) + { + // Destroy the previous line, and all to 'to_before' + //if (i >= 2) + // destroy_row_from = it-2; + //else + // destroy_row_from = it-1; + destroy_row_from = it; + destroy_row_from_used = true; + //--destroy_row_from; + } + + if (!destroy_row_to_used && it->m_ListStart > check_point_row_end) + { + destroy_row_to = it; + destroy_row_to_used = true; + + // If it isn't the last row, we'll add another row to delete, + // just so we can see if the last restorted line is + // identical to what it was before. If it isn't, then we'll + // have to continue. + // 'check_point_row_start' is where we store how the that + // line looked. + if (destroy_row_to != m_CharacterPositions.end()) + { + check_point_row_start = destroy_row_to->m_ListStart; + check_point_row_end = check_point_row_start + (int)destroy_row_to->m_ListOfX.size(); + if (destroy_row_to->m_ListOfX.empty()) + ++check_point_row_end; + } + else + check_point_row_start = check_point_row_end = -1; + + ++destroy_row_to; + break; + } + } + + if (!destroy_row_from_used) + { + destroy_row_from = m_CharacterPositions.end(); + --destroy_row_from; + + current_line = destroy_row_from; + } + + if (!destroy_row_to_used) + { + destroy_row_to = m_CharacterPositions.end(); + check_point_row_start = check_point_row_end = -1; + } + + if (destroy_row_to != m_CharacterPositions.end()) + to = destroy_row_to->m_ListStart; // notice it will iterate [from, to[, so it will never reach to. + else + to = static_cast(m_Caption.length()); + + + // Set current line, new rows will be added before current_line, so + // we'll choose the destroy_row_to, because it won't be deleted + // in the coming erase. + current_line = destroy_row_to; + + m_CharacterPositions.erase(destroy_row_from, destroy_row_to); + } + // else, the for loop will end naturally. + } + } + // This is kind of special, when we renew a some lines, then the last + // one will sometimes end with a space (' '), that really should + // be omitted when word-wrapping. So we'll check if the last row + // we'll add has got the same value as the next row. + if (current_line != m_CharacterPositions.end()) + { + if (row.m_ListStart + (int)row.m_ListOfX.size() == current_line->m_ListStart) + row.m_ListOfX.resize(row.m_ListOfX.size()-1); + } + + // add the final row (even if empty) + m_CharacterPositions.insert(current_line, row); + + if (m_ScrollBar) + { + GetScrollBar(0).SetScrollRange(m_CharacterPositions.size() * font.GetLineSpacing() + m_BufferZone * 2.f); + GetScrollBar(0).SetScrollSpace(m_CachedActualSize.GetHeight()); + } +} + +int CInput::GetMouseHoveringTextPosition() const +{ + if (m_CharacterPositions.empty()) + return 0; + + // Return position + int retPosition; + + std::list::const_iterator current = m_CharacterPositions.begin(); + + CPos mouse = m_pGUI.GetMousePos(); + + if (m_MultiLine) + { + float scroll = 0.f; + if (m_ScrollBar) + scroll = GetScrollBarPos(0); + + // Now get the height of the font. + // TODO: Get the real font + CFontMetrics font(CStrIntern(m_Font.ToUTF8())); + float spacing = (float)font.GetLineSpacing(); + + // Change mouse position relative to text. + mouse -= m_CachedActualSize.TopLeft(); + mouse.x -= m_BufferZone; + mouse.y += scroll - m_BufferZone; + + int row = (int)((mouse.y) / spacing); + + if (row < 0) + row = 0; + + if (row > (int)m_CharacterPositions.size()-1) + row = (int)m_CharacterPositions.size()-1; + + // TODO Gee (2004-11-21): Okay, I need a 'std::list' for some reasons, but I would really like to + // be able to get the specific element here. This is hopefully a temporary hack. + + for (int i = 0; i < row; ++i) + ++current; + } + else + { + // current is already set to begin, + // but we'll change the mouse.x to fit our horizontal scrolling + mouse -= m_CachedActualSize.TopLeft(); + mouse.x -= m_BufferZone - m_HorizontalScroll; + // mouse.y is moot + } + + retPosition = current->m_ListStart; + + // Okay, now loop through the glyphs to find the appropriate X position + float dummy; + retPosition += GetXTextPosition(current, mouse.x, dummy); + + return retPosition; +} + +// Does not process horizontal scrolling, 'x' must be modified before inputted. +int CInput::GetXTextPosition(const std::list::const_iterator& current, const float& x, float& wanted) const +{ + int ret = 0; + float previous = 0.f; + int i = 0; + + for (std::vector::const_iterator it = current->m_ListOfX.begin(); + it != current->m_ListOfX.end(); + ++it, ++i) + { + if (*it >= x) + { + if (x - previous >= *it - x) + ret += i+1; + else + ret += i; + + break; + } + previous = *it; + } + // If a position wasn't found, we will assume the last + // character of that line. + if (i == (int)current->m_ListOfX.size()) + { + ret += i; + wanted = x; + } + else + wanted = 0.f; + + return ret; +} + +void CInput::DeleteCurSelection() +{ + int virtualFrom; + int virtualTo; + + if (m_iBufferPos_Tail >= m_iBufferPos) + { + virtualFrom = m_iBufferPos; + virtualTo = m_iBufferPos_Tail; + } + else + { + virtualFrom = m_iBufferPos_Tail; + virtualTo = m_iBufferPos; + } + + m_Caption = + m_Caption.Left(virtualFrom) + + m_Caption.Right(static_cast(m_Caption.length()) - virtualTo); + + UpdateText(virtualFrom, virtualTo, virtualFrom); + + // Remove selection + m_iBufferPos_Tail = -1; + m_iBufferPos = virtualFrom; + UpdateBufferPositionSetting(); +} + +bool CInput::SelectingText() const +{ + return m_iBufferPos_Tail != -1 && + m_iBufferPos_Tail != m_iBufferPos; +} + +float CInput::GetTextAreaWidth() +{ + if (m_ScrollBar && GetScrollBar(0).GetStyle()) + return m_CachedActualSize.GetWidth() - m_BufferZone * 2.f - GetScrollBar(0).GetStyle()->m_Width; + + return m_CachedActualSize.GetWidth() - m_BufferZone * 2.f; +} + +void CInput::UpdateAutoScroll() +{ + // Autoscrolling up and down + if (m_MultiLine) + { + if (!m_ScrollBar) + return; + + const float scroll = GetScrollBar(0).GetPos(); + + // Now get the height of the font. + // TODO: Get the real font + CFontMetrics font(CStrIntern(m_Font.ToUTF8())); + float spacing = (float)font.GetLineSpacing(); + //float height = font.GetHeight(); + + // TODO Gee (2004-11-21): Okay, I need a 'std::list' for some reasons, but I would really like to + // be able to get the specific element here. This is hopefully a temporary hack. + + std::list::iterator current = m_CharacterPositions.begin(); + int row = 0; + while (current != m_CharacterPositions.end()) + { + if (m_iBufferPos >= current->m_ListStart && + m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size()) + break; + + ++current; + ++row; + } + + // If scrolling down + if (-scroll + static_cast(row + 1) * spacing + m_BufferZone * 2.f > m_CachedActualSize.GetHeight()) + { + // Scroll so the selected row is shown completely, also with m_BufferZone length to the edge. + GetScrollBar(0).SetPos(static_cast(row + 1) * spacing - m_CachedActualSize.GetHeight() + m_BufferZone * 2.f); + } + // If scrolling up + else if (-scroll + (float)row * spacing < 0.f) + { + // Scroll so the selected row is shown completely, also with m_BufferZone length to the edge. + GetScrollBar(0).SetPos((float)row * spacing); + } + } + else // autoscrolling left and right + { + // Get X position of position: + if (m_CharacterPositions.empty()) + return; + + float x_position = 0.f; + float x_total = 0.f; + if (!m_CharacterPositions.begin()->m_ListOfX.empty()) + { + + // Get position of m_iBufferPos + if ((int)m_CharacterPositions.begin()->m_ListOfX.size() >= m_iBufferPos && + m_iBufferPos > 0) + x_position = m_CharacterPositions.begin()->m_ListOfX[m_iBufferPos-1]; + + // Get complete length: + x_total = m_CharacterPositions.begin()->m_ListOfX[m_CharacterPositions.begin()->m_ListOfX.size()-1]; + } + + // Check if outside to the right + if (x_position - m_HorizontalScroll + m_BufferZone * 2.f > m_CachedActualSize.GetWidth()) + m_HorizontalScroll = x_position - m_CachedActualSize.GetWidth() + m_BufferZone * 2.f; + + // Check if outside to the left + if (x_position - m_HorizontalScroll < 0.f) + m_HorizontalScroll = x_position; + + // Check if the text doesn't even fill up to the right edge even though scrolling is done. + if (m_HorizontalScroll != 0.f && + x_total - m_HorizontalScroll + m_BufferZone * 2.f < m_CachedActualSize.GetWidth()) + m_HorizontalScroll = x_total - m_CachedActualSize.GetWidth() + m_BufferZone * 2.f; + + // Now this is the fail-safe, if x_total isn't even the length of the control, + // remove all scrolling + if (x_total + m_BufferZone * 2.f < m_CachedActualSize.GetWidth()) + m_HorizontalScroll = 0.f; + } +} Property changes on: ps/trunk/source/gui/ObjectTypes/CInput.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CList.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/CList.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CList.h (revision 23028) @@ -0,0 +1,151 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CLIST +#define INCLUDED_CLIST + +#include "gui/CGUISprite.h" +#include "gui/ObjectBases/IGUIScrollBarOwner.h" +#include "gui/ObjectBases/IGUITextOwner.h" +#include "gui/SettingTypes/CGUIList.h" + +#include + +/** + * Create a list of elements, where one can be selected + * by the user. The control will use a pre-processed + * text-object for each element, which will be managed + * by the IGUITextOwner structure. + * + * A scroll-bar will appear when needed. This will be + * achieved with the IGUIScrollBarOwner structure. + */ +class CList : public IGUIObject, public IGUIScrollBarOwner, public IGUITextOwner +{ + GUI_OBJECT(CList) + +public: + CList(CGUI& pGUI); + virtual ~CList(); + + /** + * @see IGUIObject#ResetStates() + */ + virtual void ResetStates(); + + /** + * @see IGUIObject#UpdateCachedSize() + */ + virtual void UpdateCachedSize(); + + /** + * Adds an item last to the list. + */ + virtual void AddItem(const CStrW& str, const CStrW& data); + +protected: + + /** + * Sets up text, should be called every time changes has been + * made that can change the visual. + */ + virtual void SetupText(); + + /** + * @see IGUIObject#HandleMessage() + */ + virtual void HandleMessage(SGUIMessage& Message); + + /** + * Handle events manually to catch keyboard inputting. + */ + virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev); + + /** + * Draws the List box + */ + virtual void Draw(); + + /** + * Easy select elements functions + */ + virtual void SelectNextElement(); + virtual void SelectPrevElement(); + virtual void SelectFirstElement(); + virtual void SelectLastElement(); + + /** + * Handle the \ tag. + */ + virtual bool HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile); + + // Called every time the auto-scrolling should be checked. + void UpdateAutoScroll(); + + // Extended drawing interface, this is so that classes built on the this one + // can use other sprite names. + virtual void DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor); + + // Get the area of the list. This is so that it can easily be changed, like in CDropDown + // where the area is not equal to m_CachedActualSize. + virtual CRect GetListRect() const { return m_CachedActualSize; } + + // Returns whether SetupText() has run since the last message was received + // (and thus whether list items have possibly changed). + virtual bool GetModified() const { return m_Modified; } + + /** + * List of each element's relative y position. Will be + * one larger than m_Items, because it will end with the + * bottom of the last element. First element will always + * be zero, but still stored for easy handling. + */ + std::vector m_ItemsYPositions; + + virtual int GetHoveredItem(); + + // Settings + float m_BufferZone; + CStrW m_Font; + bool m_ScrollBar; + CStr m_ScrollBarStyle; + CStrW m_SoundDisabled; + CStrW m_SoundSelected; + CGUISpriteInstance m_Sprite; + CGUISpriteInstance m_SpriteSelectArea; + i32 m_CellID; + EAlign m_TextAlign; + CGUIColor m_TextColor; + CGUIColor m_TextColorSelected; + i32 m_Selected; + bool m_AutoScroll; + i32 m_Hovered; + CGUIList m_List; + CGUIList m_ListData; + +private: + // Whether the list's items have been modified since last handling a message. + bool m_Modified; + + // Used for doubleclick registration + int m_PrevSelectedItem; + + // Last time a click on an item was issued + double m_LastItemClickTime; +}; + +#endif // INCLUDED_CLIST Property changes on: ps/trunk/source/gui/ObjectTypes/CList.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/COList.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/COList.cpp (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/COList.cpp (revision 23028) @@ -0,0 +1,442 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "COList.h" + +#include "gui/CGUI.h" +#include "gui/IGUIScrollBar.h" +#include "gui/SettingTypes/CGUIColor.h" +#include "gui/SettingTypes/CGUIList.h" +#include "i18n/L10n.h" +#include "ps/CLogger.h" + +const float SORT_SPRITE_DIM = 16.0f; +const CPos COLUMN_SHIFT = CPos(0, 4); + +COList::COList(CGUI& pGUI) + : CList(pGUI), + m_SpriteHeading(), + m_Sortable(), + m_SelectedColumn(), + m_SelectedColumnOrder(), + m_SpriteAsc(), + m_SpriteDesc(), + m_SpriteNotSorted() +{ + RegisterSetting("sprite_heading", m_SpriteHeading); + RegisterSetting("sortable", m_Sortable); // The actual sorting is done in JS for more versatility + RegisterSetting("selected_column", m_SelectedColumn); + RegisterSetting("selected_column_order", m_SelectedColumnOrder); + RegisterSetting("sprite_asc", m_SpriteAsc); // Show the order of sorting + RegisterSetting("sprite_desc", m_SpriteDesc); + RegisterSetting("sprite_not_sorted", m_SpriteNotSorted); +} + +void COList::SetupText() +{ + m_ItemsYPositions.resize(m_List.m_Items.size() + 1); + + // Delete all generated texts. Some could probably be saved, + // but this is easier, and this function will never be called + // continuously, or even often, so it'll probably be okay. + m_GeneratedTexts.clear(); + + m_TotalAvailableColumnWidth = GetListRect().GetWidth(); + // remove scrollbar if applicable + if (m_ScrollBar && GetScrollBar(0).GetStyle()) + m_TotalAvailableColumnWidth -= GetScrollBar(0).GetStyle()->m_Width; + + m_HeadingHeight = SORT_SPRITE_DIM; // At least the size of the sorting sprite + + for (const COListColumn& column : m_Columns) + { + float width = column.m_Width; + if (column.m_Width > 0 && column.m_Width < 1) + width *= m_TotalAvailableColumnWidth; + + CGUIString gui_string; + gui_string.SetValue(column.m_Heading); + + const CGUIText& text = AddText(gui_string, m_Font, width, m_BufferZone); + m_HeadingHeight = std::max(m_HeadingHeight, text.GetSize().cy + COLUMN_SHIFT.y); + } + + // Generate texts + float buffered_y = 0.f; + + for (size_t i = 0; i < m_List.m_Items.size(); ++i) + { + m_ItemsYPositions[i] = buffered_y; + float shift = 0.0f; + for (const COListColumn& column : m_Columns) + { + float width = column.m_Width; + if (column.m_Width > 0 && column.m_Width < 1) + width *= m_TotalAvailableColumnWidth; + + CGUIText* text; + if (!column.m_List.m_Items[i].GetOriginalString().empty()) + text = &AddText(column.m_List.m_Items[i], m_Font, width, m_BufferZone); + else + { + // Minimum height of a space character of the current font size + CGUIString align_string; + align_string.SetValue(L" "); + text = &AddText(align_string, m_Font, width, m_BufferZone); + } + shift = std::max(shift, text->GetSize().cy); + } + buffered_y += shift; + } + + m_ItemsYPositions[m_List.m_Items.size()] = buffered_y; + + if (m_ScrollBar) + { + CRect rect = GetListRect(); + GetScrollBar(0).SetScrollRange(m_ItemsYPositions.back()); + GetScrollBar(0).SetScrollSpace(rect.GetHeight()); + + GetScrollBar(0).SetX(rect.right); + GetScrollBar(0).SetY(rect.top); + GetScrollBar(0).SetZ(GetBufferedZ()); + GetScrollBar(0).SetLength(rect.bottom - rect.top); + } +} + +CRect COList::GetListRect() const +{ + return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0); +} + +void COList::HandleMessage(SGUIMessage& Message) +{ + CList::HandleMessage(Message); + + switch (Message.type) + { + // If somebody clicks on the column heading + case GUIM_MOUSE_PRESS_LEFT: + { + if (!m_Sortable) + return; + + const CPos& mouse = m_pGUI.GetMousePos(); + if (!m_CachedActualSize.PointInside(mouse)) + return; + + float xpos = 0; + for (const COListColumn& column : m_Columns) + { + if (column.m_Hidden) + continue; + + float width = column.m_Width; + // Check if it's a decimal value, and if so, assume relative positioning. + if (column.m_Width < 1 && column.m_Width > 0) + width *= m_TotalAvailableColumnWidth; + CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0); + if (mouse.x >= leftTopCorner.x && + mouse.x < leftTopCorner.x + width && + mouse.y < leftTopCorner.y + m_HeadingHeight) + { + if (column.m_Id != m_SelectedColumn) + { + SetSetting("selected_column_order", -1, true); + CStr selected_column = column.m_Id; + SetSetting("selected_column", selected_column, true); + } + else + SetSetting("selected_column_order", -m_SelectedColumnOrder, true); + + ScriptEvent("selectioncolumnchange"); + PlaySound(m_SoundSelected); + return; + } + xpos += width; + } + return; + } + default: + return; + } +} + +bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile) +{ + #define ELMT(x) int elmt_##x = pFile->GetElementID(#x) + #define ATTR(x) int attr_##x = pFile->GetAttributeID(#x) + ELMT(item); + ELMT(column); + ELMT(translatableAttribute); + ATTR(id); + ATTR(context); + + if (child.GetNodeName() == elmt_item) + { + AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8()); + return true; + } + else if (child.GetNodeName() == elmt_column) + { + COListColumn column; + + for (XMBAttribute attr : child.GetAttributes()) + { + CStr attr_name(pFile->GetAttributeString(attr.Name)); + CStr attr_value(attr.Value); + + if (attr_name == "color") + { + if (!CGUI::ParseString(&m_pGUI, attr_value.FromUTF8(), column.m_TextColor)) + LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str()); + } + else if (attr_name == "id") + { + column.m_Id = attr_value; + } + else if (attr_name == "hidden") + { + bool hidden = false; + if (!CGUI::ParseString(&m_pGUI, attr_value.FromUTF8(), hidden)) + LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str()); + else + column.m_Hidden = hidden; + } + else if (attr_name == "width") + { + float width; + if (!CGUI::ParseString(&m_pGUI, attr_value.FromUTF8(), width)) + LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str()); + else + { + // Check if it's a relative value, and save as decimal if so. + if (attr_value.find("%") != std::string::npos) + width = width / 100.f; + column.m_Width = width; + } + } + else if (attr_name == "heading") + { + column.m_Heading = attr_value.FromUTF8(); + } + } + + for (XMBElement grandchild : child.GetChildNodes()) + { + if (grandchild.GetNodeName() != elmt_translatableAttribute) + continue; + + CStr attributeName(grandchild.GetAttributes().GetNamedItem(attr_id)); + // only the heading is translatable for list column + if (attributeName.empty() || attributeName != "heading") + { + LOGERROR("GUI: translatable attribute in olist column that isn't a heading. (object: %s)", this->GetPresentableName().c_str()); + continue; + } + + CStr value(grandchild.GetText()); + if (value.empty()) + continue; + + CStr context(grandchild.GetAttributes().GetNamedItem(attr_context)); // Read the context if any. + if (!context.empty()) + { + CStr translatedValue(g_L10n.TranslateWithContext(context, value)); + column.m_Heading = translatedValue.FromUTF8(); + } + else + { + CStr translatedValue(g_L10n.Translate(value)); + column.m_Heading = translatedValue.FromUTF8(); + } + } + + m_Columns.emplace_back(std::move(column)); + return true; + } + + return false; +} + +void COList::AdditionalChildrenHandled() +{ + SetupText(); + + // Do this after the last push_back call to avoid iterator invalidation + for (COListColumn& column : m_Columns) + { + RegisterSetting("list_" + column.m_Id, column.m_List); + RegisterSetting("hidden_" + column.m_Id, column.m_Hidden); + } +} + +void COList::DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor) +{ + const float bz = GetBufferedZ(); + + if (m_ScrollBar) + IGUIScrollBarOwner::Draw(); + + CRect rect = GetListRect(); + + m_pGUI.DrawSprite(sprite, m_CellID, bz, rect); + + float scroll = 0.f; + if (m_ScrollBar) + scroll = GetScrollBar(0).GetPos(); + + // Draw item selection + if (selected != -1) + { + ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size()); + + // Get rectangle of selection: + CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, + rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll); + + if (rect_sel.top <= rect.bottom && + rect_sel.bottom >= rect.top) + { + if (rect_sel.bottom > rect.bottom) + rect_sel.bottom = rect.bottom; + if (rect_sel.top < rect.top) + rect_sel.top = rect.top; + + if (m_ScrollBar) + { + // Remove any overlapping area of the scrollbar. + if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && + rect_sel.right <= GetScrollBar(0).GetOuterRect().right) + rect_sel.right = GetScrollBar(0).GetOuterRect().left; + + if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && + rect_sel.left < GetScrollBar(0).GetOuterRect().right) + rect_sel.left = GetScrollBar(0).GetOuterRect().right; + } + + // Draw item selection + m_pGUI.DrawSprite(sprite_selected, m_CellID, bz + 0.05f, rect_sel); + } + } + + // Draw line above column header + CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right, + m_CachedActualSize.top + m_HeadingHeight); + m_pGUI.DrawSprite(m_SpriteHeading, m_CellID, bz, rect_head); + + // Draw column headers + float xpos = 0; + size_t col = 0; + for (const COListColumn& column : m_Columns) + { + if (column.m_Hidden) + { + ++col; + continue; + } + + // Check if it's a decimal value, and if so, assume relative positioning. + float width = column.m_Width; + if (column.m_Width < 1 && column.m_Width > 0) + width *= m_TotalAvailableColumnWidth; + + CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0); + + // Draw sort arrows in colum header + if (m_Sortable) + { + const CGUISpriteInstance* sprite; + if (m_SelectedColumn == column.m_Id) + { + if (m_SelectedColumnOrder == 0) + LOGERROR("selected_column_order must not be 0"); + + if (m_SelectedColumnOrder != -1) + sprite = &m_SpriteAsc; + else + sprite = &m_SpriteDesc; + } + else + sprite = &m_SpriteNotSorted; + + m_pGUI.DrawSprite(*sprite, m_CellID, bz + 0.1f, CRect(leftTopCorner + CPos(width - SORT_SPRITE_DIM, 0), leftTopCorner + CPos(width, SORT_SPRITE_DIM))); + } + + // Draw column header text + DrawText(col, textcolor, leftTopCorner + COLUMN_SHIFT, bz + 0.1f, rect_head); + xpos += width; + ++col; + } + + // Draw list items for each column + const size_t objectsCount = m_Columns.size(); + for (size_t i = 0; i < m_List.m_Items.size(); ++i) + { + if (m_ItemsYPositions[i+1] - scroll < 0 || + m_ItemsYPositions[i] - scroll > rect.GetHeight()) + continue; + + const float rowHeight = m_ItemsYPositions[i+1] - m_ItemsYPositions[i]; + + // Clipping area (we'll have to substract the scrollbar) + CRect cliparea = GetListRect(); + + if (m_ScrollBar) + { + if (cliparea.right > GetScrollBar(0).GetOuterRect().left && + cliparea.right <= GetScrollBar(0).GetOuterRect().right) + cliparea.right = GetScrollBar(0).GetOuterRect().left; + + if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && + cliparea.left < GetScrollBar(0).GetOuterRect().right) + cliparea.left = GetScrollBar(0).GetOuterRect().right; + } + + // Draw all items for that column + xpos = 0; + size_t col = 0; + for (const COListColumn& column : m_Columns) + { + if (column.m_Hidden) + { + ++col; + continue; + } + + // Determine text position and width + const CPos textPos = rect.TopLeft() + CPos(xpos, -scroll + m_ItemsYPositions[i]); + + float width = column.m_Width; + // Check if it's a decimal value, and if so, assume relative positioning. + if (column.m_Width < 1 && column.m_Width > 0) + width *= m_TotalAvailableColumnWidth; + + // Clip text to the column (to prevent drawing text into the neighboring column) + CRect cliparea2 = cliparea; + cliparea2.right = std::min(cliparea2.right, textPos.x + width); + cliparea2.bottom = std::min(cliparea2.bottom, textPos.y + rowHeight); + + // Draw list item + DrawText(objectsCount * (i +/*Heading*/1) + col, column.m_TextColor, textPos, bz + 0.1f, cliparea2); + xpos += width; + ++col; + } + } +} Property changes on: ps/trunk/source/gui/ObjectTypes/COList.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/ObjectTypes/CProgressBar.h =================================================================== --- ps/trunk/source/gui/ObjectTypes/CProgressBar.h (nonexistent) +++ ps/trunk/source/gui/ObjectTypes/CProgressBar.h (revision 23028) @@ -0,0 +1,53 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CPROGRESSBAR +#define INCLUDED_CPROGRESSBAR + +#include "gui/ObjectBases/IGUIObject.h" +#include "gui/CGUISprite.h" + +/** + * Object used to draw a value (e.g. progress) from 0 to 100 visually. + */ +class CProgressBar : public IGUIObject +{ + GUI_OBJECT(CProgressBar) + +public: + CProgressBar(CGUI& pGUI); + virtual ~CProgressBar(); + +protected: + /** + * Draws the progress bar + */ + virtual void Draw(); + + // If caption is set, make sure it's within the interval 0-100 + /** + * @see IGUIObject#HandleMessage() + */ + void HandleMessage(SGUIMessage& Message); + + // Settings + CGUISpriteInstance m_SpriteBackground; + CGUISpriteInstance m_SpriteBar; + float m_Caption; +}; + +#endif // INCLUDED_CPROGRESSBAR Property changes on: ps/trunk/source/gui/ObjectTypes/CProgressBar.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/gui/CGUI.cpp =================================================================== --- ps/trunk/source/gui/CGUI.cpp (revision 23027) +++ ps/trunk/source/gui/CGUI.cpp (revision 23028) @@ -1,1348 +1,1346 @@ /* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "CGUI.h" -// Types - when including them into the engine. -#include "CButton.h" -#include "CChart.h" -#include "CCheckBox.h" -#include "CDropDown.h" -#include "CImage.h" -#include "CInput.h" -#include "CList.h" -#include "COList.h" -#include "CProgressBar.h" -#include "CRadioButton.h" -#include "CSlider.h" -#include "CText.h" -#include "CTooltip.h" -#include "MiniMap.h" - #include "gui/IGUIScrollBar.h" +#include "gui/ObjectTypes/CButton.h" +#include "gui/ObjectTypes/CChart.h" +#include "gui/ObjectTypes/CCheckBox.h" +#include "gui/ObjectTypes/CDropDown.h" +#include "gui/ObjectTypes/CImage.h" +#include "gui/ObjectTypes/CInput.h" +#include "gui/ObjectTypes/CList.h" +#include "gui/ObjectTypes/CMiniMap.h" +#include "gui/ObjectTypes/COList.h" +#include "gui/ObjectTypes/CProgressBar.h" +#include "gui/ObjectTypes/CRadioButton.h" +#include "gui/ObjectTypes/CSlider.h" +#include "gui/ObjectTypes/CText.h" +#include "gui/ObjectTypes/CTooltip.h" +#include "gui/Scripting/ScriptFunctions.h" #include "i18n/L10n.h" #include "lib/bits.h" #include "lib/input.h" #include "lib/sysdep/sysdep.h" #include "lib/timer.h" #include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/GameSetup/Config.h" #include "ps/Globals.h" #include "ps/Hotkey.h" #include "ps/Profile.h" #include "ps/Pyrogenesis.h" #include "ps/XML/Xeromyces.h" #include "renderer/Renderer.h" -#include "scripting/ScriptFunctions.h" #include "scriptinterface/ScriptInterface.h" #include extern int g_yres; const double SELECT_DBLCLICK_RATE = 0.5; const u32 MAX_OBJECT_DEPTH = 100; // Max number of nesting for GUI includes. Used to detect recursive inclusion InReaction CGUI::HandleEvent(const SDL_Event_* ev) { InReaction ret = IN_PASS; if (ev->ev.type == SDL_HOTKEYDOWN || ev->ev.type == SDL_HOTKEYUP) { const char* hotkey = static_cast(ev->ev.user.data1); if (m_GlobalHotkeys.find(hotkey) != m_GlobalHotkeys.end() && ev->ev.type == SDL_HOTKEYDOWN) { ret = IN_HANDLED; JSContext* cx = m_ScriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedObject globalObj(cx, &GetGlobalObject().toObject()); JS::RootedValue result(cx); JS_CallFunctionValue(cx, globalObj, m_GlobalHotkeys[hotkey], JS::HandleValueArray::empty(), &result); } std::map >::iterator it = m_HotkeyObjects.find(hotkey); if (it != m_HotkeyObjects.end()) for (IGUIObject* const& obj : it->second) { if (ev->ev.type == SDL_HOTKEYDOWN) ret = obj->SendEvent(GUIM_PRESSED, "press"); else ret = obj->SendEvent(GUIM_RELEASED, "release"); } } else if (ev->ev.type == SDL_MOUSEMOTION) { // Yes the mouse position is stored as float to avoid // constant conversions when operating in a // float-based environment. m_MousePos = CPos((float)ev->ev.motion.x / g_GuiScale, (float)ev->ev.motion.y / g_GuiScale); SGUIMessage msg(GUIM_MOUSE_MOTION); m_BaseObject.RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::HandleMessage, msg); } // Update m_MouseButtons. (BUTTONUP is handled later.) else if (ev->ev.type == SDL_MOUSEBUTTONDOWN) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: case SDL_BUTTON_RIGHT: case SDL_BUTTON_MIDDLE: m_MouseButtons |= Bit(ev->ev.button.button); break; default: break; } } // Update m_MousePos (for delayed mouse button events) CPos oldMousePos = m_MousePos; if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP) { m_MousePos = CPos((float)ev->ev.button.x / g_GuiScale, (float)ev->ev.button.y / g_GuiScale); } // Only one object can be hovered IGUIObject* pNearest = nullptr; // TODO Gee: (2004-09-08) Big TODO, don't do the below if the SDL_Event is something like a keypress! try { PROFILE("mouse events"); // TODO Gee: Optimizations needed! // these two recursive function are quite overhead heavy. // pNearest will after this point at the hovered object, possibly nullptr pNearest = FindObjectUnderMouse(); // Now we'll call UpdateMouseOver on *all* objects, // we'll input the one hovered, and they will each // update their own data and send messages accordingly m_BaseObject.RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::UpdateMouseOver, static_cast(pNearest)); if (ev->ev.type == SDL_MOUSEBUTTONDOWN) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: // Focus the clicked object (or focus none if nothing clicked on) SetFocusedObject(pNearest); if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_PRESS_LEFT, "mouseleftpress"); break; case SDL_BUTTON_RIGHT: if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_PRESS_RIGHT, "mouserightpress"); break; default: break; } } else if (ev->ev.type == SDL_MOUSEWHEEL && pNearest) { if (ev->ev.wheel.y < 0) ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_DOWN, "mousewheeldown"); else if (ev->ev.wheel.y > 0) ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_UP, "mousewheelup"); } else if (ev->ev.type == SDL_MOUSEBUTTONUP) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: if (pNearest) { double timeElapsed = timer_Time() - pNearest->m_LastClickTime[SDL_BUTTON_LEFT]; pNearest->m_LastClickTime[SDL_BUTTON_LEFT] = timer_Time(); if (timeElapsed < SELECT_DBLCLICK_RATE) ret = pNearest->SendEvent(GUIM_MOUSE_DBLCLICK_LEFT, "mouseleftdoubleclick"); else ret = pNearest->SendEvent(GUIM_MOUSE_RELEASE_LEFT, "mouseleftrelease"); } break; case SDL_BUTTON_RIGHT: if (pNearest) { double timeElapsed = timer_Time() - pNearest->m_LastClickTime[SDL_BUTTON_RIGHT]; pNearest->m_LastClickTime[SDL_BUTTON_RIGHT] = timer_Time(); if (timeElapsed < SELECT_DBLCLICK_RATE) ret = pNearest->SendEvent(GUIM_MOUSE_DBLCLICK_RIGHT, "mouserightdoubleclick"); else ret = pNearest->SendEvent(GUIM_MOUSE_RELEASE_RIGHT, "mouserightrelease"); } break; } // Reset all states on all visible objects m_BaseObject.RecurseObject(&IGUIObject::IsHidden, &IGUIObject::ResetStates); // Since the hover state will have been reset, we reload it. m_BaseObject.RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::UpdateMouseOver, static_cast(pNearest)); } } catch (PSERROR_GUI& e) { UNUSED2(e); debug_warn(L"CGUI::HandleEvent error"); // TODO Gee: Handle } // BUTTONUP's effect on m_MouseButtons is handled after // everything else, so that e.g. 'press' handlers (activated // on button up) see which mouse button had been pressed. if (ev->ev.type == SDL_MOUSEBUTTONUP) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: case SDL_BUTTON_RIGHT: case SDL_BUTTON_MIDDLE: m_MouseButtons &= ~Bit(ev->ev.button.button); break; default: break; } } // Restore m_MousePos (for delayed mouse button events) if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP) m_MousePos = oldMousePos; // Handle keys for input boxes if (GetFocusedObject()) { if ((ev->ev.type == SDL_KEYDOWN && ev->ev.key.keysym.sym != SDLK_ESCAPE && !g_keys[SDLK_LCTRL] && !g_keys[SDLK_RCTRL] && !g_keys[SDLK_LALT] && !g_keys[SDLK_RALT]) || ev->ev.type == SDL_HOTKEYDOWN || ev->ev.type == SDL_TEXTINPUT || ev->ev.type == SDL_TEXTEDITING) { ret = GetFocusedObject()->ManuallyHandleEvent(ev); } // else will return IN_PASS because we never used the button. } return ret; } void CGUI::TickObjects() { const CStr action = "tick"; m_BaseObject.RecurseObject(nullptr, &IGUIObject::ScriptEvent, action); m_Tooltip.Update(FindObjectUnderMouse(), m_MousePos, *this); } void CGUI::SendEventToAll(const CStr& EventName) { // janwas 2006-03-03: spoke with Ykkrosh about EventName case. // when registering, case is converted to lower - this avoids surprise // if someone were to get the case wrong and then not notice their // handler is never called. however, until now, the other end // (sending events here) wasn't converting to lower case, // leading to a similar problem. // now fixed; case is irrelevant since all are converted to lower. const CStr EventNameLower = EventName.LowerCase(); m_BaseObject.RecurseObject(nullptr, &IGUIObject::ScriptEvent, EventNameLower); } void CGUI::SendEventToAll(const CStr& EventName, const JS::HandleValueArray& paramData) { const CStr EventNameLower = EventName.LowerCase(); m_BaseObject.RecurseObject(nullptr, &IGUIObject::ScriptEvent, EventNameLower, paramData); } CGUI::CGUI(const shared_ptr& runtime) : m_MouseButtons(0), m_FocusedObject(nullptr), m_InternalNameNumber(0), m_BaseObject(*this) { m_ScriptInterface.reset(new ScriptInterface("Engine", "GUIPage", runtime)); m_ScriptInterface->SetCallbackData(this); GuiScriptingInit(*m_ScriptInterface); m_ScriptInterface->LoadGlobalScripts(); } CGUI::~CGUI() { for (const std::pair& p : m_pAllObjects) delete p.second; for (const std::pair& p : m_Sprites) delete p.second; } IGUIObject* CGUI::ConstructObject(const CStr& str) { std::map::iterator it = m_ObjectTypes.find(str); if (it != m_ObjectTypes.end()) return (*it->second)(*this); // Error reporting will be handled with the nullptr return. return nullptr; } void CGUI::Initialize() { // Add base types! // You can also add types outside the GUI to extend the flexibility of the GUI. // Pyrogenesis 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); AddObjectType("progressbar", &CProgressBar::ConstructObject); AddObjectType("minimap", &CMiniMap::ConstructObject); AddObjectType("input", &CInput::ConstructObject); AddObjectType("list", &CList::ConstructObject); AddObjectType("olist", &COList::ConstructObject); AddObjectType("dropdown", &CDropDown::ConstructObject); AddObjectType("tooltip", &CTooltip::ConstructObject); AddObjectType("chart", &CChart::ConstructObject); AddObjectType("slider", &CSlider::ConstructObject); } void CGUI::Draw() { // Clear the depth buffer, so the GUI is // drawn on top of everything else glClear(GL_DEPTH_BUFFER_BIT); try { m_BaseObject.RecurseObject(&IGUIObject::IsHidden, &IGUIObject::Draw); } catch (PSERROR_GUI& e) { LOGERROR("GUI draw error: %s", e.what()); } } void CGUI::DrawSprite(const CGUISpriteInstance& Sprite, int CellID, const float& Z, const CRect& Rect, const CRect& UNUSED(Clipping)) { // If the sprite doesn't exist (name == ""), don't bother drawing anything if (!Sprite) return; // TODO: Clipping? Sprite.Draw(*this, Rect, CellID, m_Sprites, Z); } void CGUI::UpdateResolution() { // Update ALL cached m_BaseObject.RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); } void CGUI::AddObject(IGUIObject* pObject) { try { m_BaseObject.AddChild(pObject); // Cache tree pObject->RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); SGUIMessage msg(GUIM_LOAD); pObject->RecurseObject(nullptr, &IGUIObject::HandleMessage, msg); } catch (PSERROR_GUI&) { throw; } } void CGUI::UpdateObjects() { // We'll fill a temporary map until we know everything succeeded map_pObjects AllObjects; try { // Fill freshly m_BaseObject.RecurseObject(nullptr, &IGUIObject::AddToPointersMap, AllObjects); } catch (PSERROR_GUI&) { throw; } // Else actually update the real one m_pAllObjects.swap(AllObjects); } bool CGUI::ObjectExists(const CStr& Name) const { return m_pAllObjects.find(Name) != m_pAllObjects.end(); } IGUIObject* CGUI::FindObjectByName(const CStr& Name) const { map_pObjects::const_iterator it = m_pAllObjects.find(Name); if (it == m_pAllObjects.end()) return nullptr; return it->second; } IGUIObject* CGUI::FindObjectUnderMouse() { IGUIObject* pNearest = nullptr; m_BaseObject.RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::ChooseMouseOverAndClosest, pNearest); return pNearest; } void CGUI::SetFocusedObject(IGUIObject* pObject) { if (pObject == m_FocusedObject) return; if (m_FocusedObject) { SGUIMessage msg(GUIM_LOST_FOCUS); m_FocusedObject->HandleMessage(msg); } m_FocusedObject = pObject; if (m_FocusedObject) { SGUIMessage msg(GUIM_GOT_FOCUS); m_FocusedObject->HandleMessage(msg); } } void CGUI::SetObjectHotkey(IGUIObject* pObject, const CStr& hotkeyTag) { if (!hotkeyTag.empty()) m_HotkeyObjects[hotkeyTag].push_back(pObject); } void CGUI::UnsetObjectHotkey(IGUIObject* pObject, const CStr& hotkeyTag) { if (hotkeyTag.empty()) return; std::vector& assignment = m_HotkeyObjects[hotkeyTag]; assignment.erase( std::remove_if( assignment.begin(), assignment.end(), [&pObject](const IGUIObject* hotkeyObject) { return pObject == hotkeyObject; }), assignment.end()); } void CGUI::SetGlobalHotkey(const CStr& hotkeyTag, JS::HandleValue function) { JSContext* cx = m_ScriptInterface->GetContext(); JSAutoRequest rq(cx); if (hotkeyTag.empty()) { JS_ReportError(cx, "Cannot assign a function to an empty hotkey identifier!"); return; } if (!function.isObject() || !JS_ObjectIsFunction(cx, &function.toObject())) { JS_ReportError(cx, "Cannot assign non-function value to global hotkey '%s'", hotkeyTag.c_str()); return; } UnsetGlobalHotkey(hotkeyTag); m_GlobalHotkeys[hotkeyTag].init(cx, function); } void CGUI::UnsetGlobalHotkey(const CStr& hotkeyTag) { m_GlobalHotkeys.erase(hotkeyTag); } const SGUIScrollBarStyle* CGUI::GetScrollBarStyle(const CStr& style) const { std::map::const_iterator it = m_ScrollBarStyles.find(style); if (it == m_ScrollBarStyles.end()) return nullptr; return &it->second; } /** * @callgraph */ void CGUI::LoadXmlFile(const VfsPath& Filename, boost::unordered_set& Paths) { Paths.insert(Filename); CXeromyces XeroFile; if (XeroFile.Load(g_VFS, Filename, "gui") != PSRETURN_OK) return; XMBElement node = XeroFile.GetRoot(); CStr root_name(XeroFile.GetElementString(node.GetNodeName())); try { if (root_name == "objects") { Xeromyces_ReadRootObjects(node, &XeroFile, Paths); // Re-cache all values so these gets cached too. //UpdateResolution(); } else if (root_name == "sprites") Xeromyces_ReadRootSprites(node, &XeroFile); else if (root_name == "styles") Xeromyces_ReadRootStyles(node, &XeroFile); else if (root_name == "setup") Xeromyces_ReadRootSetup(node, &XeroFile); else debug_warn(L"CGUI::LoadXmlFile error"); } catch (PSERROR_GUI& e) { LOGERROR("Errors loading GUI file %s (%u)", Filename.string8(), e.getCode()); return; } } //=================================================================== // XML Reading Xeromyces Specific Sub-Routines //=================================================================== void CGUI::Xeromyces_ReadRootObjects(XMBElement Element, CXeromyces* pFile, boost::unordered_set& Paths) { int el_script = pFile->GetElementID("script"); std::vector > subst; // Iterate main children // they should all be or