mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-05-01 14:27:59 +03:00
Merge remote-tracking branch 'scrawl/myguiplugin'
This commit is contained in:
commit
9b7f61b4ba
44 changed files with 930 additions and 638 deletions
|
@ -91,6 +91,14 @@ add_component_dir (ogreinit
|
|||
ogreinit ogreplugin
|
||||
)
|
||||
|
||||
add_component_dir (widgets
|
||||
box imagebutton
|
||||
)
|
||||
|
||||
add_component_dir (fontloader
|
||||
fontloader
|
||||
)
|
||||
|
||||
add_component_dir (version
|
||||
version
|
||||
)
|
||||
|
@ -112,6 +120,12 @@ if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
|
|||
QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES})
|
||||
endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE)
|
||||
add_definitions(-fPIC)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR})
|
||||
|
|
373
components/fontloader/fontloader.cpp
Normal file
373
components/fontloader/fontloader.cpp
Normal file
|
@ -0,0 +1,373 @@
|
|||
#include "fontloader.hpp"
|
||||
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <OgreTextureManager.h>
|
||||
|
||||
#include <MyGUI_ResourceManager.h>
|
||||
#include <MyGUI_FontManager.h>
|
||||
#include <MyGUI_ResourceManualFont.h>
|
||||
#include <MyGUI_XmlDocument.h>
|
||||
#include <MyGUI_FactoryManager.h>
|
||||
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
unsigned long utf8ToUnicode(const std::string& utf8)
|
||||
{
|
||||
size_t i = 0;
|
||||
unsigned long unicode;
|
||||
size_t todo;
|
||||
unsigned char ch = utf8[i++];
|
||||
if (ch <= 0x7F)
|
||||
{
|
||||
unicode = ch;
|
||||
todo = 0;
|
||||
}
|
||||
else if (ch <= 0xBF)
|
||||
{
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
}
|
||||
else if (ch <= 0xDF)
|
||||
{
|
||||
unicode = ch&0x1F;
|
||||
todo = 1;
|
||||
}
|
||||
else if (ch <= 0xEF)
|
||||
{
|
||||
unicode = ch&0x0F;
|
||||
todo = 2;
|
||||
}
|
||||
else if (ch <= 0xF7)
|
||||
{
|
||||
unicode = ch&0x07;
|
||||
todo = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
}
|
||||
for (size_t j = 0; j < todo; ++j)
|
||||
{
|
||||
unsigned char ch = utf8[i++];
|
||||
if (ch < 0x80 || ch > 0xBF)
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
unicode <<= 6;
|
||||
unicode += ch & 0x3F;
|
||||
}
|
||||
if (unicode >= 0xD800 && unicode <= 0xDFFF)
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
if (unicode > 0x10FFFF)
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
|
||||
return unicode;
|
||||
}
|
||||
|
||||
// getUtf8, aka the worst function ever written.
|
||||
// This includes various hacks for dealing with Morrowind's .fnt files that are *mostly*
|
||||
// in the expected win12XX encoding, but also have randomly swapped characters sometimes.
|
||||
// Looks like the Morrowind developers found standard encodings too boring and threw in some twists for fun.
|
||||
std::string getUtf8 (unsigned char c, ToUTF8::Utf8Encoder& encoder, ToUTF8::FromType encoding)
|
||||
{
|
||||
if (encoding == ToUTF8::WINDOWS_1250)
|
||||
{
|
||||
// Hacks for polish font
|
||||
unsigned char win1250;
|
||||
std::map<unsigned char, unsigned char> conv;
|
||||
conv[0x80] = 0xc6;
|
||||
conv[0x81] = 0x9c;
|
||||
conv[0x82] = 0xe6;
|
||||
conv[0x83] = 0xb3;
|
||||
conv[0x84] = 0xf1;
|
||||
conv[0x85] = 0xb9;
|
||||
conv[0x86] = 0xbf;
|
||||
conv[0x87] = 0x9f;
|
||||
conv[0x88] = 0xea;
|
||||
conv[0x89] = 0xea;
|
||||
conv[0x8a] = 0x0; // not contained in win1250
|
||||
conv[0x8b] = 0x0; // not contained in win1250
|
||||
conv[0x8c] = 0x8f;
|
||||
conv[0x8d] = 0xaf;
|
||||
conv[0x8e] = 0xa5;
|
||||
conv[0x8f] = 0x8c;
|
||||
conv[0x90] = 0xca;
|
||||
conv[0x93] = 0xa3;
|
||||
conv[0x94] = 0xf6;
|
||||
conv[0x95] = 0xf3;
|
||||
conv[0x96] = 0xaf;
|
||||
conv[0x97] = 0x8f;
|
||||
conv[0x99] = 0xd3;
|
||||
conv[0x9a] = 0xd1;
|
||||
conv[0x9c] = 0x0; // not contained in win1250
|
||||
conv[0xa0] = 0xb9;
|
||||
conv[0xa1] = 0xaf;
|
||||
conv[0xa2] = 0xf3;
|
||||
conv[0xa3] = 0xbf;
|
||||
conv[0xa4] = 0x0; // not contained in win1250
|
||||
conv[0xe1] = 0x8c;
|
||||
// Can't remember if this was supposed to read 0xe2, or is it just an extraneous copypaste?
|
||||
//conv[0xe1] = 0x8c;
|
||||
conv[0xe3] = 0x0; // not contained in win1250
|
||||
conv[0xf5] = 0x0; // not contained in win1250
|
||||
|
||||
if (conv.find(c) != conv.end())
|
||||
win1250 = conv[c];
|
||||
else
|
||||
win1250 = c;
|
||||
return encoder.getUtf8(std::string(1, win1250));
|
||||
}
|
||||
else
|
||||
return encoder.getUtf8(std::string(1, c));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
FontLoader::FontLoader(ToUTF8::FromType encoding)
|
||||
{
|
||||
if (encoding == ToUTF8::WINDOWS_1252)
|
||||
mEncoding = ToUTF8::CP437;
|
||||
else
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
void FontLoader::loadAllFonts(bool exportToFile)
|
||||
{
|
||||
Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups ();
|
||||
for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it)
|
||||
{
|
||||
Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt");
|
||||
for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource)
|
||||
{
|
||||
loadFont(*resource, exportToFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} Point;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float u1; // appears unused, always 0
|
||||
Point top_left;
|
||||
Point top_right;
|
||||
Point bottom_left;
|
||||
Point bottom_right;
|
||||
float width;
|
||||
float height;
|
||||
float u2; // appears unused, always 0
|
||||
float kerning;
|
||||
float ascent;
|
||||
} GlyphInfo;
|
||||
|
||||
void FontLoader::loadFont(const std::string &fileName, bool exportToFile)
|
||||
{
|
||||
Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName);
|
||||
|
||||
float fontSize;
|
||||
int one;
|
||||
file->read(&fontSize, sizeof(fontSize));
|
||||
|
||||
file->read(&one, sizeof(int));
|
||||
assert(one == 1);
|
||||
file->read(&one, sizeof(int));
|
||||
assert(one == 1);
|
||||
|
||||
char name_[284];
|
||||
file->read(name_, sizeof(name_));
|
||||
std::string name(name_);
|
||||
|
||||
GlyphInfo data[256];
|
||||
file->read(data, sizeof(data));
|
||||
file->close();
|
||||
|
||||
// Create the font texture
|
||||
std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex";
|
||||
Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename);
|
||||
|
||||
int width, height;
|
||||
bitmapFile->read(&width, sizeof(int));
|
||||
bitmapFile->read(&height, sizeof(int));
|
||||
|
||||
std::vector<Ogre::uchar> textureData;
|
||||
textureData.resize(width*height*4);
|
||||
bitmapFile->read(&textureData[0], width*height*4);
|
||||
bitmapFile->close();
|
||||
|
||||
std::string resourceName;
|
||||
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
|
||||
resourceName = "Magic Cards";
|
||||
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
|
||||
resourceName = "Century Gothic";
|
||||
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
|
||||
resourceName = "Daedric";
|
||||
else
|
||||
return; // no point in loading it, since there is no way of using additional fonts
|
||||
|
||||
std::string textureName = name;
|
||||
Ogre::Image image;
|
||||
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
|
||||
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
width, height, 0, Ogre::PF_BYTE_RGBA);
|
||||
texture->loadImage(image);
|
||||
|
||||
if (exportToFile)
|
||||
image.save(resourceName + ".png");
|
||||
|
||||
// Register the font with MyGUI
|
||||
MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>(
|
||||
MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont"));
|
||||
|
||||
// We need to emulate loading from XML because the data members are private as of mygui 3.2.0
|
||||
MyGUI::xml::Document xmlDocument;
|
||||
MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont");
|
||||
root->addAttribute("name", resourceName);
|
||||
|
||||
MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property");
|
||||
defaultHeight->addAttribute("key", "DefaultHeight");
|
||||
defaultHeight->addAttribute("value", fontSize);
|
||||
MyGUI::xml::ElementPtr source = root->createChild("Property");
|
||||
source->addAttribute("key", "Source");
|
||||
source->addAttribute("value", std::string(textureName));
|
||||
MyGUI::xml::ElementPtr codes = root->createChild("Codes");
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
float x1 = data[i].top_left.x*width;
|
||||
float y1 = data[i].top_left.y*height;
|
||||
float w = data[i].top_right.x*width - x1;
|
||||
float h = data[i].bottom_left.y*height - y1;
|
||||
|
||||
ToUTF8::Utf8Encoder encoder(mEncoding);
|
||||
unsigned long unicodeVal = utf8ToUnicode(getUtf8(i, encoder, mEncoding));
|
||||
|
||||
MyGUI::xml::ElementPtr code = codes->createChild("Code");
|
||||
code->addAttribute("index", unicodeVal);
|
||||
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||
+ MyGUI::utility::toString(y1) + " "
|
||||
+ MyGUI::utility::toString(w) + " "
|
||||
+ MyGUI::utility::toString(h));
|
||||
code->addAttribute("advance", data[i].width);
|
||||
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||
code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height));
|
||||
|
||||
// More hacks! The french game uses several win1252 characters that are not included
|
||||
// in the cp437 encoding of the font. Fall back to similar available characters.
|
||||
if (mEncoding == ToUTF8::CP437)
|
||||
{
|
||||
std::multimap<int, int> additional; // <cp437, unicode>
|
||||
additional.insert(std::make_pair(39, 0x2019)); // apostrophe
|
||||
additional.insert(std::make_pair(45, 0x2013)); // dash
|
||||
additional.insert(std::make_pair(45, 0x2014)); // dash
|
||||
additional.insert(std::make_pair(34, 0x201D)); // right double quotation mark
|
||||
additional.insert(std::make_pair(34, 0x201C)); // left double quotation mark
|
||||
additional.insert(std::make_pair(44, 0x201A));
|
||||
additional.insert(std::make_pair(44, 0x201E));
|
||||
additional.insert(std::make_pair(43, 0x2020));
|
||||
additional.insert(std::make_pair(94, 0x02C6));
|
||||
additional.insert(std::make_pair(37, 0x2030));
|
||||
additional.insert(std::make_pair(83, 0x0160));
|
||||
additional.insert(std::make_pair(60, 0x2039));
|
||||
additional.insert(std::make_pair(79, 0x0152));
|
||||
additional.insert(std::make_pair(90, 0x017D));
|
||||
additional.insert(std::make_pair(39, 0x2019));
|
||||
additional.insert(std::make_pair(126, 0x02DC));
|
||||
additional.insert(std::make_pair(84, 0x2122));
|
||||
additional.insert(std::make_pair(83, 0x0161));
|
||||
additional.insert(std::make_pair(62, 0x203A));
|
||||
additional.insert(std::make_pair(111, 0x0153));
|
||||
additional.insert(std::make_pair(122, 0x017E));
|
||||
additional.insert(std::make_pair(89, 0x0178));
|
||||
additional.insert(std::make_pair(156, 0x00A2));
|
||||
additional.insert(std::make_pair(46, 0x2026));
|
||||
|
||||
for (std::multimap<int, int>::iterator it = additional.begin(); it != additional.end(); ++it)
|
||||
{
|
||||
if (it->first != i)
|
||||
continue;
|
||||
|
||||
MyGUI::xml::ElementPtr code = codes->createChild("Code");
|
||||
code->addAttribute("index", it->second);
|
||||
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||
+ MyGUI::utility::toString(y1) + " "
|
||||
+ MyGUI::utility::toString(w) + " "
|
||||
+ MyGUI::utility::toString(h));
|
||||
code->addAttribute("advance", data[i].width);
|
||||
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||
code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height));
|
||||
}
|
||||
}
|
||||
|
||||
// ASCII vertical bar, use this as text input cursor
|
||||
if (i == 124)
|
||||
{
|
||||
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||
cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor);
|
||||
cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||
+ MyGUI::utility::toString(y1) + " "
|
||||
+ MyGUI::utility::toString(w) + " "
|
||||
+ MyGUI::utility::toString(h));
|
||||
cursorCode->addAttribute("advance", data[i].width);
|
||||
cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||
cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height));
|
||||
}
|
||||
|
||||
// Question mark, use for NotDefined marker (used for glyphs not existing in the font)
|
||||
if (i == 63)
|
||||
{
|
||||
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||
cursorCode->addAttribute("index", MyGUI::FontCodeType::NotDefined);
|
||||
cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||
+ MyGUI::utility::toString(y1) + " "
|
||||
+ MyGUI::utility::toString(w) + " "
|
||||
+ MyGUI::utility::toString(h));
|
||||
cursorCode->addAttribute("advance", data[i].width);
|
||||
cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||
cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height));
|
||||
}
|
||||
}
|
||||
|
||||
// These are required as well, but the fonts don't provide them
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
MyGUI::FontCodeType::Enum type;
|
||||
if(i == 0)
|
||||
type = MyGUI::FontCodeType::Selected;
|
||||
else if (i == 1)
|
||||
type = MyGUI::FontCodeType::SelectedBack;
|
||||
|
||||
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||
cursorCode->addAttribute("index", type);
|
||||
cursorCode->addAttribute("coord", "0 0 0 0");
|
||||
cursorCode->addAttribute("advance", "0");
|
||||
cursorCode->addAttribute("bearing", "0 0");
|
||||
cursorCode->addAttribute("size", "0 0");
|
||||
}
|
||||
|
||||
if (exportToFile)
|
||||
{
|
||||
xmlDocument.createDeclaration();
|
||||
xmlDocument.save(resourceName + ".xml");
|
||||
}
|
||||
|
||||
font->deserialization(root, MyGUI::Version(3,2,0));
|
||||
|
||||
MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName());
|
||||
MyGUI::ResourceManager::getInstance().addResource(font);
|
||||
}
|
||||
|
||||
}
|
28
components/fontloader/fontloader.hpp
Normal file
28
components/fontloader/fontloader.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef MWGUI_FONTLOADER_H
|
||||
#define MWGUI_FONTLOADER_H
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
|
||||
/// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre
|
||||
class FontLoader
|
||||
{
|
||||
public:
|
||||
FontLoader (ToUTF8::FromType encoding);
|
||||
|
||||
/// @param exportToFile export the converted fonts (Images and XML with glyph metrics) to files?
|
||||
void loadAllFonts (bool exportToFile);
|
||||
|
||||
private:
|
||||
ToUTF8::FromType mEncoding;
|
||||
|
||||
/// @param exportToFile export the converted font (Image and XML with glyph metrics) to files?
|
||||
void loadFont (const std::string& fileName, bool exportToFile);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
407
components/widgets/box.cpp
Normal file
407
components/widgets/box.cpp
Normal file
|
@ -0,0 +1,407 @@
|
|||
#include "box.hpp"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w)
|
||||
{
|
||||
MyGUI::Widget * parent = w->getParent();
|
||||
if (parent != 0)
|
||||
{
|
||||
if (mExpandDirection == MyGUI::Align::Left)
|
||||
{
|
||||
int hdiff = getRequestedSize ().width - w->getSize().width;
|
||||
w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0));
|
||||
}
|
||||
w->setSize(getRequestedSize ());
|
||||
|
||||
while (parent != 0)
|
||||
{
|
||||
Box * b = dynamic_cast<Box*>(parent);
|
||||
if (b)
|
||||
b->notifyChildrenSizeChanged();
|
||||
else
|
||||
break;
|
||||
parent = parent->getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MyGUI::IntSize AutoSizedTextBox::getRequestedSize()
|
||||
{
|
||||
return getTextSize();
|
||||
}
|
||||
|
||||
void AutoSizedTextBox::setCaption(const MyGUI::UString& _value)
|
||||
{
|
||||
TextBox::setCaption(_value);
|
||||
|
||||
notifySizeChange (this);
|
||||
}
|
||||
|
||||
void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value)
|
||||
{
|
||||
if (_key == "ExpandDirection")
|
||||
{
|
||||
mExpandDirection = MyGUI::Align::parse (_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
TextBox::setPropertyOverride (_key, _value);
|
||||
}
|
||||
}
|
||||
|
||||
MyGUI::IntSize AutoSizedEditBox::getRequestedSize()
|
||||
{
|
||||
if (getAlign().isHStretch())
|
||||
throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")");
|
||||
return MyGUI::IntSize(getSize().width, getTextSize().height);
|
||||
}
|
||||
|
||||
void AutoSizedEditBox::setCaption(const MyGUI::UString& _value)
|
||||
{
|
||||
EditBox::setCaption(_value);
|
||||
|
||||
notifySizeChange (this);
|
||||
}
|
||||
|
||||
void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value)
|
||||
{
|
||||
if (_key == "ExpandDirection")
|
||||
{
|
||||
mExpandDirection = MyGUI::Align::parse (_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditBox::setPropertyOverride (_key, _value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MyGUI::IntSize AutoSizedButton::getRequestedSize()
|
||||
{
|
||||
MyGUI::IntSize padding(24, 8);
|
||||
if (isUserString("TextPadding"))
|
||||
padding = MyGUI::IntSize::parse(getUserString("TextPadding"));
|
||||
|
||||
MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(padding.width,padding.height);
|
||||
return size;
|
||||
}
|
||||
|
||||
void AutoSizedButton::setCaption(const MyGUI::UString& _value)
|
||||
{
|
||||
Button::setCaption(_value);
|
||||
|
||||
notifySizeChange (this);
|
||||
}
|
||||
|
||||
void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value)
|
||||
{
|
||||
if (_key == "ExpandDirection")
|
||||
{
|
||||
mExpandDirection = MyGUI::Align::parse (_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Button::setPropertyOverride (_key, _value);
|
||||
}
|
||||
}
|
||||
|
||||
Box::Box()
|
||||
: mSpacing(4)
|
||||
, mPadding(0)
|
||||
, mAutoResize(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Box::notifyChildrenSizeChanged ()
|
||||
{
|
||||
align();
|
||||
}
|
||||
|
||||
bool Box::_setPropertyImpl(const std::string& _key, const std::string& _value)
|
||||
{
|
||||
if (_key == "Spacing")
|
||||
mSpacing = MyGUI::utility::parseValue<int>(_value);
|
||||
else if (_key == "Padding")
|
||||
mPadding = MyGUI::utility::parseValue<int>(_value);
|
||||
else if (_key == "AutoResize")
|
||||
mAutoResize = MyGUI::utility::parseValue<bool>(_value);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HBox::align ()
|
||||
{
|
||||
unsigned int count = getChildCount ();
|
||||
size_t h_stretched_count = 0;
|
||||
int total_width = 0;
|
||||
int total_height = 0;
|
||||
std::vector< std::pair<MyGUI::IntSize, bool> > sizes;
|
||||
sizes.resize(count);
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
MyGUI::Widget* w = getChildAt(i);
|
||||
bool hstretch = w->getUserString ("HStretch") == "true";
|
||||
bool hidden = w->getUserString("Hidden") == "true";
|
||||
if (hidden)
|
||||
continue;
|
||||
h_stretched_count += hstretch;
|
||||
AutoSizedWidget* aw = dynamic_cast<AutoSizedWidget*>(w);
|
||||
if (aw)
|
||||
{
|
||||
sizes[i] = std::make_pair(aw->getRequestedSize (), hstretch);
|
||||
total_width += aw->getRequestedSize ().width;
|
||||
total_height = std::max(total_height, aw->getRequestedSize ().height);
|
||||
}
|
||||
else
|
||||
{
|
||||
sizes[i] = std::make_pair(w->getSize(), hstretch);
|
||||
total_width += w->getSize().width;
|
||||
if (!(w->getUserString("VStretch") == "true"))
|
||||
total_height = std::max(total_height, w->getSize().height);
|
||||
}
|
||||
|
||||
if (i != count-1)
|
||||
total_width += mSpacing;
|
||||
}
|
||||
|
||||
if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height))
|
||||
{
|
||||
setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int curX = 0;
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
if (i == 0)
|
||||
curX += mPadding;
|
||||
|
||||
MyGUI::Widget* w = getChildAt(i);
|
||||
|
||||
bool hidden = w->getUserString("Hidden") == "true";
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
bool vstretch = w->getUserString ("VStretch") == "true";
|
||||
int max_height = getSize().height - mPadding*2;
|
||||
int height = vstretch ? max_height : sizes[i].first.height;
|
||||
|
||||
MyGUI::IntCoord widgetCoord;
|
||||
widgetCoord.left = curX;
|
||||
widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2;
|
||||
int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count
|
||||
: sizes[i].first.width;
|
||||
widgetCoord.width = width;
|
||||
widgetCoord.height = height;
|
||||
w->setCoord(widgetCoord);
|
||||
curX += width;
|
||||
|
||||
if (i != count-1)
|
||||
curX += mSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
void HBox::setPropertyOverride(const std::string& _key, const std::string& _value)
|
||||
{
|
||||
if (!Box::_setPropertyImpl (_key, _value))
|
||||
MyGUI::Widget::setPropertyOverride(_key, _value);
|
||||
}
|
||||
|
||||
void HBox::setSize (const MyGUI::IntSize& _value)
|
||||
{
|
||||
MyGUI::Widget::setSize (_value);
|
||||
align();
|
||||
}
|
||||
|
||||
void HBox::setCoord (const MyGUI::IntCoord& _value)
|
||||
{
|
||||
MyGUI::Widget::setCoord (_value);
|
||||
align();
|
||||
}
|
||||
|
||||
void HBox::onWidgetCreated(MyGUI::Widget* _widget)
|
||||
{
|
||||
align();
|
||||
}
|
||||
|
||||
MyGUI::IntSize HBox::getRequestedSize ()
|
||||
{
|
||||
MyGUI::IntSize size(0,0);
|
||||
for (unsigned int i = 0; i < getChildCount (); ++i)
|
||||
{
|
||||
bool hidden = getChildAt(i)->getUserString("Hidden") == "true";
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
AutoSizedWidget* w = dynamic_cast<AutoSizedWidget*>(getChildAt(i));
|
||||
if (w)
|
||||
{
|
||||
MyGUI::IntSize requested = w->getRequestedSize ();
|
||||
size.height = std::max(size.height, requested.height);
|
||||
size.width = size.width + requested.width;
|
||||
if (i != getChildCount()-1)
|
||||
size.width += mSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
MyGUI::IntSize requested = getChildAt(i)->getSize ();
|
||||
size.height = std::max(size.height, requested.height);
|
||||
|
||||
if (getChildAt(i)->getUserString("HStretch") != "true")
|
||||
size.width = size.width + requested.width;
|
||||
|
||||
if (i != getChildCount()-1)
|
||||
size.width += mSpacing;
|
||||
}
|
||||
size.height += mPadding*2;
|
||||
size.width += mPadding*2;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void VBox::align ()
|
||||
{
|
||||
unsigned int count = getChildCount ();
|
||||
size_t v_stretched_count = 0;
|
||||
int total_height = 0;
|
||||
int total_width = 0;
|
||||
std::vector< std::pair<MyGUI::IntSize, bool> > sizes;
|
||||
sizes.resize(count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
MyGUI::Widget* w = getChildAt(i);
|
||||
|
||||
bool hidden = w->getUserString("Hidden") == "true";
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
bool vstretch = w->getUserString ("VStretch") == "true";
|
||||
v_stretched_count += vstretch;
|
||||
AutoSizedWidget* aw = dynamic_cast<AutoSizedWidget*>(w);
|
||||
if (aw)
|
||||
{
|
||||
sizes[i] = std::make_pair(aw->getRequestedSize (), vstretch);
|
||||
total_height += aw->getRequestedSize ().height;
|
||||
total_width = std::max(total_width, aw->getRequestedSize ().width);
|
||||
}
|
||||
else
|
||||
{
|
||||
sizes[i] = std::make_pair(w->getSize(), vstretch);
|
||||
total_height += w->getSize().height;
|
||||
|
||||
if (!(w->getUserString("HStretch") == "true"))
|
||||
total_width = std::max(total_width, w->getSize().width);
|
||||
}
|
||||
|
||||
if (i != count-1)
|
||||
total_height += mSpacing;
|
||||
}
|
||||
|
||||
if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height))
|
||||
{
|
||||
setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int curY = 0;
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
if (i==0)
|
||||
curY += mPadding;
|
||||
|
||||
MyGUI::Widget* w = getChildAt(i);
|
||||
|
||||
bool hidden = w->getUserString("Hidden") == "true";
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
bool hstretch = w->getUserString ("HStretch") == "true";
|
||||
int maxWidth = getSize().width - mPadding*2;
|
||||
int width = hstretch ? maxWidth : sizes[i].first.width;
|
||||
|
||||
MyGUI::IntCoord widgetCoord;
|
||||
widgetCoord.top = curY;
|
||||
widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2;
|
||||
int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count
|
||||
: sizes[i].first.height;
|
||||
widgetCoord.height = height;
|
||||
widgetCoord.width = width;
|
||||
w->setCoord(widgetCoord);
|
||||
curY += height;
|
||||
|
||||
if (i != count-1)
|
||||
curY += mSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
void VBox::setPropertyOverride(const std::string& _key, const std::string& _value)
|
||||
{
|
||||
if (!Box::_setPropertyImpl (_key, _value))
|
||||
MyGUI::Widget::setPropertyOverride(_key, _value);
|
||||
}
|
||||
|
||||
void VBox::setSize (const MyGUI::IntSize& _value)
|
||||
{
|
||||
MyGUI::Widget::setSize (_value);
|
||||
align();
|
||||
}
|
||||
|
||||
void VBox::setCoord (const MyGUI::IntCoord& _value)
|
||||
{
|
||||
MyGUI::Widget::setCoord (_value);
|
||||
align();
|
||||
}
|
||||
|
||||
MyGUI::IntSize VBox::getRequestedSize ()
|
||||
{
|
||||
MyGUI::IntSize size(0,0);
|
||||
for (unsigned int i = 0; i < getChildCount (); ++i)
|
||||
{
|
||||
bool hidden = getChildAt(i)->getUserString("Hidden") == "true";
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
AutoSizedWidget* w = dynamic_cast<AutoSizedWidget*>(getChildAt(i));
|
||||
if (w)
|
||||
{
|
||||
MyGUI::IntSize requested = w->getRequestedSize ();
|
||||
size.width = std::max(size.width, requested.width);
|
||||
size.height = size.height + requested.height;
|
||||
if (i != getChildCount()-1)
|
||||
size.height += mSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
MyGUI::IntSize requested = getChildAt(i)->getSize ();
|
||||
size.width = std::max(size.width, requested.width);
|
||||
|
||||
if (getChildAt(i)->getUserString("VStretch") != "true")
|
||||
size.height = size.height + requested.height;
|
||||
|
||||
if (i != getChildCount()-1)
|
||||
size.height += mSpacing;
|
||||
}
|
||||
size.height += mPadding*2;
|
||||
size.width += mPadding*2;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void VBox::onWidgetCreated(MyGUI::Widget* _widget)
|
||||
{
|
||||
align();
|
||||
}
|
||||
|
||||
}
|
118
components/widgets/box.hpp
Normal file
118
components/widgets/box.hpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#ifndef OPENMW_WIDGETS_BOX_H
|
||||
#define OPENMW_WIDGETS_BOX_H
|
||||
|
||||
#include <MyGUI_Widget.h>
|
||||
#include <MyGUI_TextBox.h>
|
||||
#include <MyGUI_EditBox.h>
|
||||
#include <MyGUI_Button.h>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
class AutoSizedWidget
|
||||
{
|
||||
public:
|
||||
virtual MyGUI::IntSize getRequestedSize() = 0;
|
||||
|
||||
protected:
|
||||
void notifySizeChange(MyGUI::Widget* w);
|
||||
|
||||
MyGUI::Align mExpandDirection;
|
||||
};
|
||||
|
||||
class AutoSizedTextBox : public AutoSizedWidget, public MyGUI::TextBox
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( AutoSizedTextBox )
|
||||
|
||||
public:
|
||||
virtual MyGUI::IntSize getRequestedSize();
|
||||
virtual void setCaption(const MyGUI::UString& _value);
|
||||
|
||||
protected:
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
};
|
||||
|
||||
class AutoSizedEditBox : public AutoSizedWidget, public MyGUI::EditBox
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( AutoSizedEditBox )
|
||||
|
||||
public:
|
||||
virtual MyGUI::IntSize getRequestedSize();
|
||||
virtual void setCaption(const MyGUI::UString& _value);
|
||||
|
||||
protected:
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
};
|
||||
|
||||
class AutoSizedButton : public AutoSizedWidget, public MyGUI::Button
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( AutoSizedButton )
|
||||
|
||||
public:
|
||||
virtual MyGUI::IntSize getRequestedSize();
|
||||
virtual void setCaption(const MyGUI::UString& _value);
|
||||
|
||||
protected:
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A container widget that automatically sizes its children
|
||||
* @note the box being an AutoSizedWidget as well allows to put boxes inside a box
|
||||
*/
|
||||
class Box : public AutoSizedWidget
|
||||
{
|
||||
public:
|
||||
Box();
|
||||
|
||||
void notifyChildrenSizeChanged();
|
||||
|
||||
protected:
|
||||
virtual void align() = 0;
|
||||
|
||||
virtual bool _setPropertyImpl(const std::string& _key, const std::string& _value);
|
||||
|
||||
int mSpacing; // how much space to put between elements
|
||||
|
||||
int mPadding; // outer padding
|
||||
|
||||
bool mAutoResize; // auto resize the box so that it exactly fits all elements
|
||||
};
|
||||
|
||||
class HBox : public Box, public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( HBox )
|
||||
|
||||
public:
|
||||
virtual void setSize (const MyGUI::IntSize &_value);
|
||||
virtual void setCoord (const MyGUI::IntCoord &_value);
|
||||
|
||||
protected:
|
||||
virtual void align();
|
||||
virtual MyGUI::IntSize getRequestedSize();
|
||||
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
|
||||
virtual void onWidgetCreated(MyGUI::Widget* _widget);
|
||||
};
|
||||
|
||||
class VBox : public Box, public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( VBox)
|
||||
|
||||
public:
|
||||
virtual void setSize (const MyGUI::IntSize &_value);
|
||||
virtual void setCoord (const MyGUI::IntCoord &_value);
|
||||
|
||||
protected:
|
||||
virtual void align();
|
||||
virtual MyGUI::IntSize getRequestedSize();
|
||||
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
|
||||
virtual void onWidgetCreated(MyGUI::Widget* _widget);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
64
components/widgets/imagebutton.cpp
Normal file
64
components/widgets/imagebutton.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "imagebutton.hpp"
|
||||
|
||||
#include <MyGUI_RenderManager.h>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value)
|
||||
{
|
||||
if (_key == "ImageHighlighted")
|
||||
mImageHighlighted = _value;
|
||||
else if (_key == "ImagePushed")
|
||||
mImagePushed = _value;
|
||||
else if (_key == "ImageNormal")
|
||||
{
|
||||
if (mImageNormal == "")
|
||||
{
|
||||
setImageTexture(_value);
|
||||
}
|
||||
mImageNormal = _value;
|
||||
}
|
||||
else
|
||||
ImageBox::setPropertyOverride(_key, _value);
|
||||
}
|
||||
void ImageButton::onMouseSetFocus(Widget* _old)
|
||||
{
|
||||
setImageTexture(mImageHighlighted);
|
||||
ImageBox::onMouseSetFocus(_old);
|
||||
}
|
||||
|
||||
void ImageButton::onMouseLostFocus(Widget* _new)
|
||||
{
|
||||
setImageTexture(mImageNormal);
|
||||
ImageBox::onMouseLostFocus(_new);
|
||||
}
|
||||
|
||||
void ImageButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
if (_id == MyGUI::MouseButton::Left)
|
||||
setImageTexture(mImagePushed);
|
||||
|
||||
ImageBox::onMouseButtonPressed(_left, _top, _id);
|
||||
}
|
||||
|
||||
MyGUI::IntSize ImageButton::getRequestedSize(bool logError)
|
||||
{
|
||||
MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture(mImageNormal);
|
||||
if (!texture)
|
||||
{
|
||||
if (logError)
|
||||
std::cerr << "ImageButton: can't find " << mImageNormal << std::endl;
|
||||
return MyGUI::IntSize(0,0);
|
||||
}
|
||||
return MyGUI::IntSize (texture->getWidth(), texture->getHeight());
|
||||
}
|
||||
|
||||
void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
if (_id == MyGUI::MouseButton::Left)
|
||||
setImageTexture(mImageHighlighted);
|
||||
|
||||
ImageBox::onMouseButtonReleased(_left, _top, _id);
|
||||
}
|
||||
}
|
33
components/widgets/imagebutton.hpp
Normal file
33
components/widgets/imagebutton.hpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef MWGUI_IMAGEBUTTON_H
|
||||
#define MWGUI_IMAGEBUTTON_H
|
||||
|
||||
#include <MyGUI_ImageBox.h>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief allows using different image textures depending on the button state
|
||||
*/
|
||||
class ImageButton : public MyGUI::ImageBox
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(ImageButton)
|
||||
|
||||
public:
|
||||
MyGUI::IntSize getRequestedSize(bool logError = true);
|
||||
|
||||
protected:
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
virtual void onMouseLostFocus(MyGUI::Widget* _new);
|
||||
virtual void onMouseSetFocus(MyGUI::Widget* _old);
|
||||
virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id);
|
||||
virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id);
|
||||
|
||||
std::string mImageHighlighted;
|
||||
std::string mImageNormal;
|
||||
std::string mImagePushed;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue