[deploy] Merge pull request #54 from KiwanoEngine/dev
Add StringView and ConfigIni
This commit is contained in:
commit
394c74d5e5
|
|
@ -96,9 +96,9 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\render\TextStyle.hpp" />
|
<ClInclude Include="..\..\src\kiwano\render\TextStyle.hpp" />
|
||||||
<ClInclude Include="..\..\src\kiwano\render\Texture.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Texture.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\render\TextureCache.h" />
|
<ClInclude Include="..\..\src\kiwano\render\TextureCache.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\EventTicker.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\EventTicker.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\Json.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\Json.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h" />
|
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\Logger.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\Logger.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\ResourceCache.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\ResourceCache.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\Task.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\Task.h" />
|
||||||
|
|
@ -174,8 +174,8 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\render\TextLayout.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\TextLayout.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\render\Texture.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Texture.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\render\TextureCache.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\TextureCache.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\EventTicker.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\EventTicker.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\LocalStorage.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\Logger.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\Logger.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\ResourceCache.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\ResourceCache.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\Task.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\Task.cpp" />
|
||||||
|
|
|
||||||
|
|
@ -105,9 +105,6 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\action\ActionWalk.h">
|
<ClInclude Include="..\..\src\kiwano\2d\action\ActionWalk.h">
|
||||||
<Filter>2d\action</Filter>
|
<Filter>2d\action</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h">
|
|
||||||
<Filter>utils</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\UserData.h">
|
<ClInclude Include="..\..\src\kiwano\utils\UserData.h">
|
||||||
<Filter>utils</Filter>
|
<Filter>utils</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -351,6 +348,9 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\base\component\ComponentManager.h">
|
<ClInclude Include="..\..\src\kiwano\base\component\ComponentManager.h">
|
||||||
<Filter>base\component</Filter>
|
<Filter>base\component</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h">
|
||||||
|
<Filter>utils</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
||||||
|
|
@ -401,9 +401,6 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\action\ActionWalk.cpp">
|
<ClCompile Include="..\..\src\kiwano\2d\action\ActionWalk.cpp">
|
||||||
<Filter>2d\action</Filter>
|
<Filter>2d\action</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\LocalStorage.cpp">
|
|
||||||
<Filter>utils</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\UserData.cpp">
|
<ClCompile Include="..\..\src\kiwano\utils\UserData.cpp">
|
||||||
<Filter>utils</Filter>
|
<Filter>utils</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -575,6 +572,9 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\base\component\ComponentManager.cpp">
|
<ClCompile Include="..\..\src\kiwano\base\component\ComponentManager.cpp">
|
||||||
<Filter>base\component</Filter>
|
<Filter>base\component</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp">
|
||||||
|
<Filter>utils</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="suppress_warning.ruleset" />
|
<None Include="suppress_warning.ruleset" />
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,24 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief »ù´¡×Ö·û´®ÈÝÆ÷
|
||||||
|
template <typename CharTy>
|
||||||
|
using BasicString = std::basic_string<CharTy>;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 字符串容器
|
/// @brief 字符串容器
|
||||||
using String = std::string;
|
using String = BasicString<char>;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 宽字符串容器
|
/// @brief 宽字符串容器
|
||||||
using WideString = std::wstring;
|
using WideString = BasicString<wchar_t>;
|
||||||
|
|
||||||
|
|
||||||
namespace strings
|
namespace strings
|
||||||
{
|
{
|
||||||
|
|
@ -53,4 +60,351 @@ WideString NarrowToWide(const String& str);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief »ù´¡³£×Ö·û´®ÊÓͼ
|
||||||
|
template <typename CharTy>
|
||||||
|
class BasicStringView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = CharTy;
|
||||||
|
using pointer = CharTy*;
|
||||||
|
using const_pointer = const CharTy*;
|
||||||
|
using reference = CharTy&;
|
||||||
|
using const_reference = const CharTy&;
|
||||||
|
using traits_type = std::char_traits<CharTy>;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using string_type = BasicString<CharTy>;
|
||||||
|
|
||||||
|
BasicStringView()
|
||||||
|
: ptr_(nullptr)
|
||||||
|
, count_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicStringView(const_pointer c_str)
|
||||||
|
{
|
||||||
|
ptr_ = c_str;
|
||||||
|
if (c_str)
|
||||||
|
{
|
||||||
|
count_ = traits_type::length(c_str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicStringView(const_pointer c_str, size_type count)
|
||||||
|
{
|
||||||
|
ptr_ = c_str;
|
||||||
|
if (c_str)
|
||||||
|
{
|
||||||
|
count_ = count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicStringView(const string_type& str)
|
||||||
|
: ptr_(str.c_str())
|
||||||
|
, count_(str.length())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicStringView(const BasicStringView& rhs)
|
||||||
|
: ptr_(rhs.ptr_)
|
||||||
|
, count_(rhs.count_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const value_type* Data() const
|
||||||
|
{
|
||||||
|
return ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsEmpty() const
|
||||||
|
{
|
||||||
|
return !ptr_ || !count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_type Find(value_type ch) const
|
||||||
|
{
|
||||||
|
const auto ptr = traits_type::find(ptr_, count_, ch);
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
return ptr - ptr_;
|
||||||
|
}
|
||||||
|
return string_type::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline BasicStringView SubStr(size_type pos, size_type count = string_type::npos) const
|
||||||
|
{
|
||||||
|
if (pos >= count_)
|
||||||
|
return BasicStringView();
|
||||||
|
|
||||||
|
if (count == string_type::npos)
|
||||||
|
return BasicStringView(ptr_ + pos, count_ - pos);
|
||||||
|
|
||||||
|
KGE_ASSERT(pos + count <= count_);
|
||||||
|
return BasicStringView(ptr_ + pos, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_type GetLength() const
|
||||||
|
{
|
||||||
|
return count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline value_type At(size_type index) const
|
||||||
|
{
|
||||||
|
return operator[](index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline value_type operator[](size_type index) const
|
||||||
|
{
|
||||||
|
if (IsEmpty() || index >= count_)
|
||||||
|
throw std::out_of_range("operator[] out of index");
|
||||||
|
return ptr_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator string_type() const
|
||||||
|
{
|
||||||
|
return string_type(ptr_, count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline BasicStringView& operator=(const BasicStringView& rhs)
|
||||||
|
{
|
||||||
|
ptr_ = rhs.ptr_;
|
||||||
|
count_ = rhs.count_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
//
|
||||||
|
// Iterators for BasicStringView
|
||||||
|
//
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
const value_type* ptr_;
|
||||||
|
size_type pos_;
|
||||||
|
size_type count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using value_type = value_type;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using reference = value_type&;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
|
inline Iterator(pointer ptr, size_type pos, size_type count)
|
||||||
|
: ptr_(ptr)
|
||||||
|
, pos_(pos)
|
||||||
|
, count_(count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator(const Iterator& rhs)
|
||||||
|
: ptr_(rhs.ptr_)
|
||||||
|
, pos_(rhs.pos_)
|
||||||
|
, count_(rhs.count_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator& operator=(const Iterator& rhs)
|
||||||
|
{
|
||||||
|
ptr_ = rhs.ptr_;
|
||||||
|
pos_ = rhs.pos_;
|
||||||
|
count_ = rhs.count_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const value_type& operator*() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(pos_ < count_);
|
||||||
|
return ptr_[pos_];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const value_type* operator->() const
|
||||||
|
{
|
||||||
|
return std::pointer_traits<pointer>::pointer_to(**this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator& operator+=(size_type count)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(pos_ + count >= 0 && pos_ + count <= count_);
|
||||||
|
pos_ += count;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator& operator-=(size_type count)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(pos_ - count >= 0 && pos_ - count <= count_);
|
||||||
|
pos_ -= count;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Iterator operator+(size_type count) const
|
||||||
|
{
|
||||||
|
Iterator iter(*this);
|
||||||
|
iter += count;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Iterator& operator-(size_type count) const
|
||||||
|
{
|
||||||
|
Iterator iter(*this);
|
||||||
|
iter -= count;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator& operator++()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(pos_ < count_);
|
||||||
|
++pos_;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator operator++(int)
|
||||||
|
{
|
||||||
|
Iterator old = (*this);
|
||||||
|
++(*this);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator& operator--()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(pos_ > 0);
|
||||||
|
--pos_;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Iterator operator--(int)
|
||||||
|
{
|
||||||
|
Iterator old = (*this);
|
||||||
|
--(*this);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const value_type& operator[](size_type index) const
|
||||||
|
{
|
||||||
|
Iterator iter = (*this + index);
|
||||||
|
return iter.ptr_[iter.pos_];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline difference_type operator-(const Iterator& other) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(ptr_ == other.ptr_ && count_ == other.count_);
|
||||||
|
return static_cast<difference_type>(pos_ - other.pos_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return ptr_ == other.ptr_ && pos_ == other.pos_ && count_ == other.count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return ptr_ < other.ptr_ || pos_ < other.pos_ || count_ < other.count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<=(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return (*this < other) || (*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator>(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return !(*this <= other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator>=(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return !(*this < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator bool() const
|
||||||
|
{
|
||||||
|
return ptr_ != nullptr && pos_ != count_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using const_iterator = Iterator;
|
||||||
|
using iterator = const_iterator;
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
using reverse_iterator = const_reverse_iterator;
|
||||||
|
|
||||||
|
inline const_iterator begin() const
|
||||||
|
{
|
||||||
|
return const_iterator(ptr_, 0, count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_iterator cbegin() const
|
||||||
|
{
|
||||||
|
return begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_iterator end() const
|
||||||
|
{
|
||||||
|
return const_iterator(ptr_, count_, count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_iterator cend() const
|
||||||
|
{
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_reverse_iterator rbegin() const
|
||||||
|
{
|
||||||
|
return const_reverse_iterator(end());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_reverse_iterator crbegin() const
|
||||||
|
{
|
||||||
|
return rbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_reverse_iterator rend() const
|
||||||
|
{
|
||||||
|
return const_reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_reverse_iterator crend() const
|
||||||
|
{
|
||||||
|
return rend();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const value_type& front() const
|
||||||
|
{
|
||||||
|
if (IsEmpty())
|
||||||
|
throw std::out_of_range("front() called on empty list");
|
||||||
|
return ptr_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const value_type& back() const
|
||||||
|
{
|
||||||
|
if (IsEmpty())
|
||||||
|
throw std::out_of_range("back() called on empty list");
|
||||||
|
return ptr_[count_];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const value_type* ptr_;
|
||||||
|
size_type count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief ×Ö·û´®ÊÓͼ
|
||||||
|
using StringView = BasicStringView<char>;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief ¿í×Ö·û´®ÊÓͼ
|
||||||
|
using WideStringView = BasicStringView<wchar_t>;
|
||||||
|
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -263,17 +263,17 @@ inline void Duration::SetMilliseconds(int64_t ms)
|
||||||
|
|
||||||
inline void Duration::SetSeconds(float seconds)
|
inline void Duration::SetSeconds(float seconds)
|
||||||
{
|
{
|
||||||
milliseconds_ = static_cast<long>(seconds * 1000.f);
|
milliseconds_ = static_cast<int64_t>(seconds * 1000.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Duration::SetMinutes(float minutes)
|
inline void Duration::SetMinutes(float minutes)
|
||||||
{
|
{
|
||||||
milliseconds_ = static_cast<long>(minutes * 60 * 1000.f);
|
milliseconds_ = static_cast<int64_t>(minutes * 60 * 1000.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Duration::SetHours(float hours)
|
inline void Duration::SetHours(float hours)
|
||||||
{
|
{
|
||||||
milliseconds_ = static_cast<long>(hours * 60 * 60 * 1000.f);
|
milliseconds_ = static_cast<int64_t>(hours * 60 * 60 * 1000.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Time::IsZero() const
|
inline bool Time::IsZero() const
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <kiwano/utils/Logger.h>
|
#include <kiwano/utils/Logger.h>
|
||||||
#include <kiwano/utils/LocalStorage.h>
|
|
||||||
#include <kiwano/utils/ResourceCache.h>
|
#include <kiwano/utils/ResourceCache.h>
|
||||||
#include <kiwano/utils/UserData.h>
|
#include <kiwano/utils/UserData.h>
|
||||||
#include <kiwano/utils/Timer.h>
|
#include <kiwano/utils/Timer.h>
|
||||||
|
|
@ -135,3 +134,4 @@
|
||||||
#include <kiwano/utils/EventTicker.h>
|
#include <kiwano/utils/EventTicker.h>
|
||||||
#include <kiwano/utils/Task.h>
|
#include <kiwano/utils/Task.h>
|
||||||
#include <kiwano/utils/TaskScheduler.h>
|
#include <kiwano/utils/TaskScheduler.h>
|
||||||
|
#include <kiwano/utils/ConfigIni.h>
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,6 @@ Application::Application()
|
||||||
Use(Renderer::GetInstance());
|
Use(Renderer::GetInstance());
|
||||||
Use(Input::GetInstance());
|
Use(Input::GetInstance());
|
||||||
Use(Director::GetInstance());
|
Use(Director::GetInstance());
|
||||||
|
|
||||||
ticker_ = Ticker::Create(0);
|
|
||||||
ticker_->Tick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
|
|
@ -76,11 +73,27 @@ void Application::Run(RunnerPtr runner, bool debug)
|
||||||
|
|
||||||
while (running_)
|
while (running_)
|
||||||
{
|
{
|
||||||
if (ticker_->Tick())
|
if (!frame_ticker_)
|
||||||
{
|
{
|
||||||
if (!runner->MainLoop(ticker_->GetDeltaTime()))
|
frame_ticker_ = Ticker::Create(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_ticker_->Tick())
|
||||||
|
{
|
||||||
|
// Execute main loop
|
||||||
|
if (!runner->MainLoop(frame_ticker_->GetDeltaTime()))
|
||||||
running_ = false;
|
running_ = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Releases CPU
|
||||||
|
Duration total_dt = frame_ticker_->GetDeltaTime() + frame_ticker_->GetErrorTime();
|
||||||
|
Duration sleep_dt = frame_ticker_->GetInterval() - total_dt;
|
||||||
|
if (sleep_dt.Milliseconds() > 1LL)
|
||||||
|
{
|
||||||
|
sleep_dt.Sleep();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->Destroy();
|
this->Destroy();
|
||||||
|
|
@ -89,19 +102,17 @@ void Application::Run(RunnerPtr runner, bool debug)
|
||||||
void Application::Pause()
|
void Application::Pause()
|
||||||
{
|
{
|
||||||
is_paused_ = true;
|
is_paused_ = true;
|
||||||
if (ticker_)
|
|
||||||
{
|
if (frame_ticker_)
|
||||||
ticker_->Pause();
|
frame_ticker_->Pause();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Resume()
|
void Application::Resume()
|
||||||
{
|
{
|
||||||
is_paused_ = false;
|
is_paused_ = false;
|
||||||
if (ticker_)
|
|
||||||
{
|
if (frame_ticker_)
|
||||||
ticker_->Resume();
|
frame_ticker_->Resume();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Quit()
|
void Application::Quit()
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,19 @@ public:
|
||||||
*/
|
*/
|
||||||
void Quit();
|
void Quit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 获取暂停状态
|
||||||
|
*/
|
||||||
|
bool IsPaused() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 添加模块
|
||||||
|
* @param[in] module 模块
|
||||||
|
*/
|
||||||
|
void Use(Module& module);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 获取程序运行器
|
* @brief 获取程序运行器
|
||||||
|
|
@ -92,22 +105,15 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 获取报时器
|
* @brief 获取帧报时器
|
||||||
*/
|
*/
|
||||||
TickerPtr GetTicker() const;
|
TickerPtr GetFrameTicker() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 获取暂停状态
|
* @brief 设置帧报时器
|
||||||
*/
|
*/
|
||||||
bool IsPaused() const;
|
void SetFrameTicker(TickerPtr ticker);
|
||||||
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 添加模块
|
|
||||||
* @param[in] module 模块
|
|
||||||
*/
|
|
||||||
void Use(Module& module);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
|
|
@ -166,7 +172,7 @@ private:
|
||||||
bool is_paused_;
|
bool is_paused_;
|
||||||
float time_scale_;
|
float time_scale_;
|
||||||
RunnerPtr runner_;
|
RunnerPtr runner_;
|
||||||
TickerPtr ticker_;
|
TickerPtr frame_ticker_;
|
||||||
List<Module*> modules_;
|
List<Module*> modules_;
|
||||||
std::mutex perform_mutex_;
|
std::mutex perform_mutex_;
|
||||||
Queue<Function<void()>> functions_to_perform_;
|
Queue<Function<void()>> functions_to_perform_;
|
||||||
|
|
@ -183,9 +189,14 @@ inline WindowPtr Application::GetMainWindow() const
|
||||||
return runner_->GetMainWindow();
|
return runner_->GetMainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TickerPtr Application::GetTicker() const
|
inline TickerPtr Application::GetFrameTicker() const
|
||||||
{
|
{
|
||||||
return ticker_;
|
return frame_ticker_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Application::SetFrameTicker(TickerPtr ticker)
|
||||||
|
{
|
||||||
|
frame_ticker_ = ticker;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Application::IsPaused() const
|
inline bool Application::IsPaused() const
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
|
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
|
||||||
#include <imm.h> // ImmAssociateContext
|
#include <imm.h> // ImmAssociateContext
|
||||||
#pragma comment(lib, "imm32.lib")
|
#pragma comment(lib, "imm32.lib")
|
||||||
|
#include <timeapi.h> // timeBeginPeriod, timeEndPeriod
|
||||||
|
#pragma comment(lib, "winmm.lib")
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -185,6 +187,8 @@ WindowWin32Impl::WindowWin32Impl()
|
||||||
// F1 - F12
|
// F1 - F12
|
||||||
for (size_t i = 0; i < 12; ++i)
|
for (size_t i = 0; i < 12; ++i)
|
||||||
key_map_[VK_F1 + i] = KeyCode(size_t(KeyCode::F1) + i);
|
key_map_[VK_F1 + i] = KeyCode(size_t(KeyCode::F1) + i);
|
||||||
|
|
||||||
|
::timeBeginPeriod(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowWin32Impl::~WindowWin32Impl()
|
WindowWin32Impl::~WindowWin32Impl()
|
||||||
|
|
@ -194,6 +198,8 @@ WindowWin32Impl::~WindowWin32Impl()
|
||||||
::DestroyWindow(handle_);
|
::DestroyWindow(handle_);
|
||||||
handle_ = nullptr;
|
handle_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::timeEndPeriod(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable)
|
void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,372 @@
|
||||||
|
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <kiwano/utils/ConfigIni.h>
|
||||||
|
#include <kiwano/core/Exception.h>
|
||||||
|
#include <fstream> // std::ifstream, std::ofstream
|
||||||
|
#include <algorithm> // std::sort, std::for_each
|
||||||
|
#include <cctype> // std::isspace
|
||||||
|
|
||||||
|
#define KGE_DEFAULT_INI_SECTION_NAME "default"
|
||||||
|
|
||||||
|
namespace kiwano
|
||||||
|
{
|
||||||
|
|
||||||
|
StringView Trim(StringView str)
|
||||||
|
{
|
||||||
|
if (!str.IsEmpty())
|
||||||
|
{
|
||||||
|
std::size_t start = 0, end = str.GetLength();
|
||||||
|
while (std::isspace(str[start]))
|
||||||
|
++start;
|
||||||
|
while (std::isspace(str[end - 1]))
|
||||||
|
--end;
|
||||||
|
|
||||||
|
if (end - start)
|
||||||
|
return StringView(str.Data() + start, end - start);
|
||||||
|
}
|
||||||
|
return StringView();
|
||||||
|
}
|
||||||
|
|
||||||
|
class IniParser
|
||||||
|
{
|
||||||
|
StringView line_;
|
||||||
|
public:
|
||||||
|
IniParser(StringView line)
|
||||||
|
: line_(line)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClearComment()
|
||||||
|
{
|
||||||
|
auto pos = line_.Find(';');
|
||||||
|
if (pos != String::npos)
|
||||||
|
{
|
||||||
|
if (pos == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (std::isspace(line_[pos - 1]))
|
||||||
|
{
|
||||||
|
line_ = Trim(line_.SubStr(0, pos - 1));
|
||||||
|
return line_.IsEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSection() const
|
||||||
|
{
|
||||||
|
return line_[0] == '[' && line_.GetLength() > 2 && line_[line_.GetLength() - 1] == ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView GetSectionName() const
|
||||||
|
{
|
||||||
|
return Trim(line_.SubStr(1, line_.GetLength() - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetKeyValue(StringView* key, StringView* value)
|
||||||
|
{
|
||||||
|
auto pos = line_.Find('=');
|
||||||
|
if (pos == String::npos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*key = Trim(line_.SubStr(0, pos));
|
||||||
|
*value = Trim(line_.SubStr(pos + 1));
|
||||||
|
|
||||||
|
return !(*key).IsEmpty() && !(*value).IsEmpty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigIniPtr ConfigIni::Create(const String& file_path)
|
||||||
|
{
|
||||||
|
ConfigIniPtr ptr = memory::New<ConfigIni>();
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
if (!ptr->Load(file_path))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::Load(const String& file_path)
|
||||||
|
{
|
||||||
|
std::ifstream ifs(file_path);
|
||||||
|
|
||||||
|
if (ifs.is_open())
|
||||||
|
{
|
||||||
|
return Load(ifs);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::Load(std::istream& istream)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String section = KGE_DEFAULT_INI_SECTION_NAME;
|
||||||
|
for (String line; std::getline(istream, line);)
|
||||||
|
{
|
||||||
|
ParseLine(line, §ion);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::Save(const String& file_path)
|
||||||
|
{
|
||||||
|
std::ofstream ofs(file_path);
|
||||||
|
|
||||||
|
if (ofs.is_open())
|
||||||
|
{
|
||||||
|
return Save(ofs);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::Save(std::ostream& os)
|
||||||
|
{
|
||||||
|
// Get all keys
|
||||||
|
Vector<String> keys;
|
||||||
|
keys.reserve(sections_.size());
|
||||||
|
std::for_each(sections_.begin(), sections_.end(), [&](SectionMap::value_type& pair) { keys.push_back(pair.first); });
|
||||||
|
|
||||||
|
// Sort for keys
|
||||||
|
std::sort(keys.begin(), keys.end());
|
||||||
|
|
||||||
|
// Output to ini
|
||||||
|
for (const auto& key : keys)
|
||||||
|
{
|
||||||
|
os << '[' << key << ']' << std::endl;
|
||||||
|
for (const auto& pair : sections_[key])
|
||||||
|
{
|
||||||
|
os << pair.first << " = " << pair.second << std::endl;
|
||||||
|
}
|
||||||
|
os << std::endl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigIni::SectionMap ConfigIni::GetSectionMap() const
|
||||||
|
{
|
||||||
|
return sections_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigIni::ValueMap ConfigIni::GetSection(const String& section) const
|
||||||
|
{
|
||||||
|
auto iter = sections_.find(section);
|
||||||
|
if (iter != sections_.end())
|
||||||
|
return iter->second;
|
||||||
|
return ValueMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
String ConfigIni::GetString(const String& section_name, const String& key) const
|
||||||
|
{
|
||||||
|
if (HasSection(section_name))
|
||||||
|
{
|
||||||
|
const auto& section = sections_.at(section_name);
|
||||||
|
|
||||||
|
auto iter_key = section.find(key);
|
||||||
|
if (iter_key != section.end())
|
||||||
|
return iter_key->second;
|
||||||
|
}
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
float ConfigIni::GetFloat(const String& section, const String& key, float default_value) const
|
||||||
|
{
|
||||||
|
String str = GetString(section, key);
|
||||||
|
if (str.empty())
|
||||||
|
return default_value;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t pos = 0;
|
||||||
|
float value = std::stof(str, &pos);
|
||||||
|
if (pos == str.size())
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument)
|
||||||
|
{
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ConfigIni::GetDouble(const String& section, const String& key, double default_value) const
|
||||||
|
{
|
||||||
|
String str = GetString(section, key);
|
||||||
|
if (str.empty())
|
||||||
|
return default_value;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t pos = 0;
|
||||||
|
double value = std::stod(str, &pos);
|
||||||
|
if (pos == str.size())
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument)
|
||||||
|
{
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConfigIni::GetInt(const String& section, const String& key, int default_value) const
|
||||||
|
{
|
||||||
|
String str = GetString(section, key);
|
||||||
|
if (str.empty())
|
||||||
|
return default_value;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t pos = 0;
|
||||||
|
int value = std::stoi(str, &pos);
|
||||||
|
if (pos == str.size())
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument)
|
||||||
|
{
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::GetBool(const String& section, const String& key, bool default_value) const
|
||||||
|
{
|
||||||
|
String str = GetString(section, key);
|
||||||
|
if (!str.empty())
|
||||||
|
{
|
||||||
|
if (str == "true" || str == "1")
|
||||||
|
return true;
|
||||||
|
else if (str == "false" || str == "0")
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::HasSection(const String& section) const
|
||||||
|
{
|
||||||
|
return !!sections_.count(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigIni::HasValue(const String& section, const String& key) const
|
||||||
|
{
|
||||||
|
if (HasSection(section))
|
||||||
|
{
|
||||||
|
return !!sections_.at(section).count(section);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetSectionMap(const SectionMap& sections)
|
||||||
|
{
|
||||||
|
sections_ = sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetSection(const String& section, const ValueMap& values)
|
||||||
|
{
|
||||||
|
sections_.insert(std::make_pair(section, values));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetString(const String& section, const String& key, const String& value)
|
||||||
|
{
|
||||||
|
if (HasSection(section))
|
||||||
|
sections_[section].insert(std::make_pair(key, value));
|
||||||
|
else
|
||||||
|
SetSection(section, ValueMap{ { key, value } });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetFloat(const String& section, const String& key, float value)
|
||||||
|
{
|
||||||
|
String str = std::to_string(value);
|
||||||
|
SetString(section, key, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetDouble(const String& section, const String& key, double value)
|
||||||
|
{
|
||||||
|
String str = std::to_string(value);
|
||||||
|
SetString(section, key, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetInt(const String& section, const String& key, int value)
|
||||||
|
{
|
||||||
|
String str = std::to_string(value);
|
||||||
|
SetString(section, key, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::SetBool(const String& section, const String& key, bool value)
|
||||||
|
{
|
||||||
|
SetString(section, key, value ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigIni::ValueMap& ConfigIni::operator[](const String& section)
|
||||||
|
{
|
||||||
|
if (!HasSection(section))
|
||||||
|
{
|
||||||
|
sections_.insert(std::make_pair(section, ValueMap()));
|
||||||
|
}
|
||||||
|
return sections_[section];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConfigIni::ValueMap& ConfigIni::operator[](const String& section) const
|
||||||
|
{
|
||||||
|
if (!HasSection(section))
|
||||||
|
{
|
||||||
|
const_cast<SectionMap&>(sections_).insert(std::make_pair(section, ValueMap()));
|
||||||
|
}
|
||||||
|
return sections_.at(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigIni::ParseLine(StringView line, String* section)
|
||||||
|
{
|
||||||
|
line = Trim(line);
|
||||||
|
if (line.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
IniParser parser(line);
|
||||||
|
if (parser.ClearComment())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parser.IsSection())
|
||||||
|
{
|
||||||
|
auto name = parser.GetSectionName();
|
||||||
|
if (name.IsEmpty())
|
||||||
|
throw Exception("Empty section name");
|
||||||
|
*section = name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView key, value;
|
||||||
|
if (!parser.GetKeyValue(&key, &value))
|
||||||
|
{
|
||||||
|
throw Exception("Parse key-value failed");
|
||||||
|
}
|
||||||
|
SetString(*section, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <kiwano/core/Common.h>
|
||||||
|
#include <kiwano/base/ObjectBase.h>
|
||||||
|
|
||||||
|
namespace kiwano
|
||||||
|
{
|
||||||
|
|
||||||
|
KGE_DECLARE_SMART_PTR(ConfigIni);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief ini格式文件
|
||||||
|
class KGE_API ConfigIni : public ObjectBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 加载 ini 文件
|
||||||
|
/// @param file_path 文件路径
|
||||||
|
static ConfigIniPtr Create(const String& file_path);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 键值字典
|
||||||
|
typedef Map<String, String> ValueMap;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief Section字典
|
||||||
|
typedef UnorderedMap<String, ValueMap> SectionMap;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 加载 ini 文件
|
||||||
|
/// @param file_path 文件路径
|
||||||
|
bool Load(const String& file_path);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 加载 ini 文件
|
||||||
|
/// @param is 输入流
|
||||||
|
bool Load(std::istream& is);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 保存至 ini 文件
|
||||||
|
/// @param file_path 文件路径
|
||||||
|
bool Save(const String& file_path);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 保存至 ini 文件
|
||||||
|
/// @param os 输出流
|
||||||
|
bool Save(std::ostream& os);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取所有section
|
||||||
|
SectionMap GetSectionMap() const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取section
|
||||||
|
/// @param section section的名称
|
||||||
|
ValueMap GetSection(const String& section) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
String GetString(const String& section, const String& key) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param default_value 不存在时的默认值
|
||||||
|
float GetFloat(const String& section, const String& key, float default_value = 0.0f) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param default_value 不存在时的默认值
|
||||||
|
double GetDouble(const String& section, const String& key, double default_value = 0.0) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param default_value 不存在时的默认值
|
||||||
|
int GetInt(const String& section, const String& key, int default_value = 0) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param default_value 不存在时的默认值
|
||||||
|
bool GetBool(const String& section, const String& key, bool default_value = false) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 是否存在section
|
||||||
|
/// @param section section的名称
|
||||||
|
bool HasSection(const String& section) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 是否存在值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
bool HasValue(const String& section, const String& key) const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置所有section
|
||||||
|
/// @param sections section字典
|
||||||
|
void SetSectionMap(const SectionMap& sections);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置section
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param values 键值字典
|
||||||
|
void SetSection(const String& section, const ValueMap& values);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param value 值
|
||||||
|
void SetString(const String& section, const String& key, const String& value);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param value 值
|
||||||
|
void SetFloat(const String& section, const String& key, float value);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param value 值
|
||||||
|
void SetDouble(const String& section, const String& key, double value);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param value 值
|
||||||
|
void SetInt(const String& section, const String& key, int value);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置值
|
||||||
|
/// @param section section的名称
|
||||||
|
/// @param key key的名称
|
||||||
|
/// @param value 值
|
||||||
|
void SetBool(const String& section, const String& key, bool value);
|
||||||
|
|
||||||
|
ValueMap& operator[](const String& section);
|
||||||
|
|
||||||
|
const ValueMap& operator[](const String& section) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ParseLine(StringView line, String* section);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SectionMap sections_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
#include <kiwano/utils/LocalStorage.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
|
||||||
{
|
|
||||||
|
|
||||||
LocalStorage::LocalStorage(const String& file_path, const String& field)
|
|
||||||
{
|
|
||||||
SetFilePath(file_path);
|
|
||||||
SetFieldName(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::Exists(const String& key) const
|
|
||||||
{
|
|
||||||
char temp[256] = { 0 };
|
|
||||||
::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), "", temp, 255, file_path_.c_str());
|
|
||||||
return temp[0] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::SaveInt(const String& key, int val) const
|
|
||||||
{
|
|
||||||
BOOL ret =
|
|
||||||
::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), std::to_string(val).c_str(), file_path_.c_str());
|
|
||||||
return ret == TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::SaveFloat(const String& key, float val) const
|
|
||||||
{
|
|
||||||
BOOL ret =
|
|
||||||
::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), std::to_string(val).c_str(), file_path_.c_str());
|
|
||||||
return ret == TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::SaveDouble(const String& key, double val) const
|
|
||||||
{
|
|
||||||
BOOL ret =
|
|
||||||
::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), std::to_string(val).c_str(), file_path_.c_str());
|
|
||||||
return ret == TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::SaveBool(const String& key, bool val) const
|
|
||||||
{
|
|
||||||
BOOL ret = ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), (val ? "1" : "0"), file_path_.c_str());
|
|
||||||
return ret == TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::SaveString(const String& key, const String& val) const
|
|
||||||
{
|
|
||||||
BOOL ret = ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), val.c_str(), file_path_.c_str());
|
|
||||||
return ret == TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LocalStorage::GetInt(const String& key, int default_value) const
|
|
||||||
{
|
|
||||||
return ::GetPrivateProfileIntA(field_name_.c_str(), key.c_str(), default_value, file_path_.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
float LocalStorage::GetFloat(const String& key, float default_value) const
|
|
||||||
{
|
|
||||||
char temp[32] = { 0 };
|
|
||||||
String default_str = std::to_string(default_value);
|
|
||||||
::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), default_str.c_str(), temp, 31, file_path_.c_str());
|
|
||||||
return std::stof(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
double LocalStorage::GetDouble(const String& key, double default_value) const
|
|
||||||
{
|
|
||||||
char temp[32] = { 0 };
|
|
||||||
String default_str = std::to_string(default_value);
|
|
||||||
::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), default_str.c_str(), temp, 31, file_path_.c_str());
|
|
||||||
return std::stod(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalStorage::GetBool(const String& key, bool default_value) const
|
|
||||||
{
|
|
||||||
int nValue = ::GetPrivateProfileIntA(field_name_.c_str(), key.c_str(), default_value ? 1 : 0, file_path_.c_str());
|
|
||||||
return nValue == TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
String LocalStorage::GetString(const String& key, const String& default_value) const
|
|
||||||
{
|
|
||||||
char temp[256] = { 0 };
|
|
||||||
::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), default_value.c_str(), temp, 255, file_path_.c_str());
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace kiwano
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <kiwano/core/Common.h>
|
|
||||||
#include <kiwano/base/ObjectBase.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
|
||||||
{
|
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(LocalStorage);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 本地存储
|
|
||||||
/// @details LocalStorage是一个简易的持久化工具,存放(字符串-值)的键值对
|
|
||||||
/// 支持的数据类型包括 (bool | int | float | double | String)
|
|
||||||
/// 例如, 保存游戏最高分, 以便下次进行游戏时读取:
|
|
||||||
/// @code
|
|
||||||
/// LocalStorage data; // 创建数据对象
|
|
||||||
/// data.SaveInt("best-score", 20); // 保存最高分 20
|
|
||||||
/// int best = data.GetInt("best-score"); // 读取之前储存的最高分
|
|
||||||
/// @endcode
|
|
||||||
class KGE_API LocalStorage : public ObjectBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 构建本地存储对象
|
|
||||||
/// @param file_path 文件储存路径
|
|
||||||
/// @param field 字段名
|
|
||||||
LocalStorage(const String& file_path = "data.ini", const String& field = "defalut");
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取文件储存路径
|
|
||||||
const String& GetFilePath() const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 设置文件储存路径
|
|
||||||
void SetFilePath(const String& file_path);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取字段名
|
|
||||||
const String& GetFieldName() const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 设置字段名
|
|
||||||
void SetFieldName(const String& field);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 判断键对应的数据是否存在
|
|
||||||
bool Exists(const String& key) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 保存 int 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param val 值
|
|
||||||
/// @return 操作是否成功
|
|
||||||
bool SaveInt(const String& key, int val) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 保存 float 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param val 值
|
|
||||||
/// @return 操作是否成功
|
|
||||||
bool SaveFloat(const String& key, float val) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 保存 double 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param val 值
|
|
||||||
/// @return 操作是否成功
|
|
||||||
bool SaveDouble(const String& key, double val) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 保存 bool 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param val 值
|
|
||||||
/// @return 操作是否成功
|
|
||||||
bool SaveBool(const String& key, bool val) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 保存 String 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param val 值
|
|
||||||
/// @return 操作是否成功
|
|
||||||
bool SaveString(const String& key, const String& val) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取 int 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param default_value 值不存在时返回的默认值
|
|
||||||
/// @return 值
|
|
||||||
int GetInt(const String& key, int default_value = 0) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取 float 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param default_value 值不存在时返回的默认值
|
|
||||||
/// @return 值
|
|
||||||
float GetFloat(const String& key, float default_value = 0.0f) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取 double 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param default_value 值不存在时返回的默认值
|
|
||||||
/// @return 值
|
|
||||||
double GetDouble(const String& key, double default_value = 0.0) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取 bool 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param default_value 值不存在时返回的默认值
|
|
||||||
/// @return 值
|
|
||||||
bool GetBool(const String& key, bool default_value = false) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取 字符串 类型的值
|
|
||||||
/// @param key 键
|
|
||||||
/// @param default_value 值不存在时返回的默认值
|
|
||||||
/// @return 值
|
|
||||||
String GetString(const String& key, const String& default_value = String()) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
String file_path_;
|
|
||||||
String field_name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline const String& LocalStorage::GetFilePath() const
|
|
||||||
{
|
|
||||||
return file_path_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const String& LocalStorage::GetFieldName() const
|
|
||||||
{
|
|
||||||
return field_name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void LocalStorage::SetFilePath(const String& file_path)
|
|
||||||
{
|
|
||||||
file_path_ = file_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void LocalStorage::SetFieldName(const String& field_name)
|
|
||||||
{
|
|
||||||
field_name_ = field_name;
|
|
||||||
}
|
|
||||||
} // namespace kiwano
|
|
||||||
|
|
@ -65,9 +65,16 @@ bool Ticker::Tick(Duration dt)
|
||||||
if (ticked_count_ == total_tick_count_)
|
if (ticked_count_ == total_tick_count_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (interval_.IsZero())
|
||||||
|
{
|
||||||
|
delta_time_ = dt;
|
||||||
|
++ticked_count_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
elapsed_time_ += dt;
|
elapsed_time_ += dt;
|
||||||
|
|
||||||
if (elapsed_time_ + error_time_ > interval_)
|
if (elapsed_time_ + error_time_ >= interval_)
|
||||||
{
|
{
|
||||||
delta_time_ = elapsed_time_;
|
delta_time_ = elapsed_time_;
|
||||||
error_time_ = (elapsed_time_ + error_time_) - interval_;
|
error_time_ = (elapsed_time_ + error_time_) - interval_;
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,10 @@ public:
|
||||||
/// @brief 设置报时间隔
|
/// @brief 设置报时间隔
|
||||||
void SetInterval(Duration interval);
|
void SetInterval(Duration interval);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取时间误差
|
||||||
|
Duration GetErrorTime() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取计时器
|
/// @brief 获取计时器
|
||||||
TimerPtr GetTimer();
|
TimerPtr GetTimer();
|
||||||
|
|
@ -140,4 +144,9 @@ inline void Ticker::SetInterval(Duration interval)
|
||||||
interval_ = interval;
|
interval_ = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Duration Ticker::GetErrorTime() const
|
||||||
|
{
|
||||||
|
return error_time_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue