<commit_before>#ifndef MANGAPP_LIBRARY_HPP
#define MANGAPP_LIBRARY_HPP

#include "archive.hpp"
#include "directory_entry.hpp"
#include "file_enumeration.hpp"
#include "sort.hpp"
#include "users.hpp"
#include "utf8.hpp"
#include "image.hpp"

#include <unordered_map>

#include <json11/json11.hpp>

#include <mstch/mstch.hpp>

namespace base
{
    namespace
    {
        std::vector<std::wstring> utf8_paths_to_utf16(std::vector<std::string> const & library_paths)
        {
            std::vector<std::wstring> utf16_paths;

            for (auto const & path : library_paths)
            {
                std::wstring utf16_str = to_utf16(path);

                utf16_paths.push_back(utf16_str);
            }

            return utf16_paths;
        }

        std::vector<std::wstring> json_to_utf16_vector(json11::Json const & library_paths)
        {
            std::vector<std::wstring> utf16_paths;

            for (auto const & element : library_paths.array_items())
            {
                json11::Json const & object = element.object_items();
                std::string utf8_str(object["path"].string_value());
                std::wstring utf16_str = to_utf16(utf8_str);

                utf16_paths.emplace_back(utf16_str);
            }

            return utf16_paths;
        }
    }

    template<class DirectoryEntryType>
    class library
    {
    public:
        typedef size_t key_type;
        typedef DirectoryEntryType directory_entry_type;
        typedef typename DirectoryEntryType::file_entry_type file_entry_type;

        typedef std::unordered_map<key_type, directory_entry_type> library_map_type;
        typedef typename library_map_type::iterator iterator;
        typedef typename library_map_type::const_iterator const_iterator;

        /**
        *  Constructor for the library. Multiple paths can be parsed.
        *
        *  @param library_paths a vector containing the file path(s)
        */
        library(std::vector<std::wstring> const & library_paths, mangapp::users & users) :
            m_entries(),
            m_users(users)
        {
            // Iterate through the libraries
            for (auto const & library_path : library_paths)
            {
                enumerate_files(library_path, file_search_flags::FlagDirectory, false,
                    [this](std::wstring const & path, file_search_flags flag)
                {
                    auto path_end_pos = path.rfind(L"/");

                    std::wstring name_str = path.substr(path_end_pos + 1);
                    std::wstring path_str(path, 0, path_end_pos + 1);

                    auto key = boost::hash<std::wstring>()(name_str);
                    m_entries.emplace(key, directory_entry_type(path_str, name_str, key));
                });
            }
        }

        library(std::vector<std::string> const & library_paths, mangapp::users & users) :
            library(utf8_paths_to_utf16(library_paths), users)
        {
        }

        library(json11::Json const & library_paths, mangapp::users & users) :
            library(json_to_utf16_vector(library_paths), users)
        {
        }

        virtual ~library()
        {
        }

        iterator begin()
        {
            return m_entries.begin();
        }

        iterator end()
        {
            return m_entries.end();
        }

        const_iterator cbegin() const
        {
            return m_entries.cbegin();
        }

        const_iterator cend() const
        {
            return m_entries.cend();
        }

        iterator find(key_type key)
        {
            return m_entries.find(key);
        }

        const_iterator find(key_type key) const
        {
            return m_entries.find(key);
        }

        key_type size() const
        {
            return m_entries.size();
        }

        mstch::map const get_list_context(std::string const & session_id) const
        {
            mstch::array library_array;

            // Enumerate all the entries the user can access
            std::vector<std::reference_wrapper<directory_entry_type const>> ordered;
            for (auto const & pair : m_entries)
            {
                size_t path_key = boost::hash<std::wstring>()(pair.second.get_path());
                if (m_users.can_access(session_id, path_key) == true)
                    ordered.push_back(std::cref(pair.second));
            }

            // Collate the entries
            std::sort(ordered.begin(), ordered.end(),
                [](std::reference_wrapper<directory_entry_type const> const & left,
                   std::reference_wrapper<directory_entry_type const> const & right) -> bool
            {
                return std::locale()(left.get().get_name(), right.get().get_name());
            });

            // Construct the array of manga/comics
            for (auto const & entry : ordered)
            {
                std::wstring utf16_name(entry.get().get_name());
                std::string utf8_name = to_utf8(utf16_name);

                library_array.emplace_back(mstch::map{
                    { "key",  std::to_string(entry.get().get_key()) },
                    { "name", utf8_name }
                });
            }

            return mstch::map({
                { "library-list", library_array }
            });
        }

        mstch::map get_files_context(std::string const & session_id, key_type key) const
        {
            auto const manga_comic_iterator = library::find(key);
            if (manga_comic_iterator != library::cend())
            {
                // Firstly, ensure the user has access
                size_t path_key = boost::hash<std::wstring>()(manga_comic_iterator->second.get_path());
                if (m_users.can_access(session_id, path_key) == false)
                    return mstch::map();

                // Enumerate all the files from the directory_entry
                std::vector<std::reference_wrapper<library::file_entry_type const>> ordered;

                std::for_each(manga_comic_iterator->second.cbegin(), manga_comic_iterator->second.cend(),
                    [&ordered](typename library::directory_entry_type::map_type::value_type const & entry)
                {
                    ordered.push_back(std::cref(entry.second));
                });

                // Sort the filenames based on a regex rule
                std::sort(ordered.begin(), ordered.end(),
                    [](std::reference_wrapper<library::file_entry_type const> const & left,
                       std::reference_wrapper<library::file_entry_type const> const & right)
                {
                    return sort::numerical_wregex_less()(left.get().get_name(), right.get().get_name());
                });

                mstch::array files_array{};

                // Construct and populate the array of files
                std::for_each(ordered.cbegin(), ordered.cend(),
                    [&files_array, key](std::reference_wrapper<library::file_entry_type const> const & value) -> void
                {
                    auto const & entry = value.get();

                    // Filter out any files that are not archives
                    if (is_archive_extension(entry.get_extension()) == true)
                    {
                        std::wstring const & utf16_name(entry.get_name());
                        std::string utf8_name = to_utf8(utf16_name);

                        files_array.emplace_back(mstch::map({
                            { "key", std::to_string(key) },
                            { "file-key", std::to_string(entry.get_key()) },
                            { "file-name", utf8_name }
                        }));
                    }
                });

                std::wstring const & utf16_name(manga_comic_iterator->second.get_name());
                std::string utf8_name = to_utf8(utf16_name);

                return mstch::map({
                    { "key", std::to_string(key) },
                    { "name", std::move(utf8_name) },
                    { "file-count", std::to_string(files_array.size()) },
                    { "files-list", std::move(files_array) },
                });
            }

            return mstch::map();
        }

        mstch::map const get_reader_context(std::string const & session_id, key_type key, key_type file_key) const
        {
            auto const entry_iterator = find(key);
            if (entry_iterator != cend())
            {
                // Ensure the user has access
                size_t path_key = boost::hash<std::wstring>()(entry_iterator->second.get_path());
                if (m_users.can_access(session_id, path_key) == false)
                    return mstch::map();

                // Find the requested archive based from its key
                auto archive_iterator = entry_iterator->second.find(file_key);
                // Was it found?
                if (archive_iterator != entry_iterator->second.cend())
                {
                    // Yes, get its path and open the archive
                    auto file_path = archive_iterator->second.get_path() + archive_iterator->second.get_name();
                    auto archive_ptr = mangapp::archive::open(file_path);
                    // Ensure we have a valid pointer
                    if (archive_ptr != nullptr)
                    {
                        mstch::array image_array;
                        mstch::array image_dropdown;
                        uint32_t image_count = 0;

                        // Populate the array of images
                        for (auto const & image_entry : *archive_ptr)
                        {
                            // Filter out any files that are not images
                            if (is_image_extension(image_entry->extension()) == true)
                            {
                                image_array.emplace_back(mstch::map({
                                    { "key", std::to_string(key) },
                                    { "file-key", std::to_string(file_key) },
                                    { "index", std::to_string(image_count) }
                                }));

                                image_dropdown.emplace_back(mstch::map({
                                    { "image-index", std::to_string(++image_count) }
                                }));
                            }
                        }

                        std::wstring const & utf16_name(entry_iterator->second.get_name());
                        std::string utf8_name = to_utf8(utf16_name);

                        return mstch::map({
                            { "name", utf8_name },
                            { "image-count", std::to_string(image_count) },
                            { "image-dropdown", image_dropdown },
                            { "image-list", image_array }
                        });
                    }
                }
            }

            return mstch::map();
        }

        /**
        *   Reads the thumbnail of a manga/comic from its folder or from an archive.
        *   Retrieval from an archive is NOT implemented yet.
        *
        *   @param key the key of the manga/comic
        *   @param index index of the archive in the folder
        *   @return a string containing the thumbnail's contents
        */
        std::string get_thumbnail(std::string const & session_id, key_type key, uint32_t index = 0) const
        {
            std::string thumb_data;

            auto const manga_comic_iterator = find(key);
            // Does the specified key exist in our map?
            if (manga_comic_iterator != cend())
            {
                // Look for an existing thumbnail
                directory_entry_type const & dir_entry = manga_comic_iterator->second;
                size_t thumb_key_1 = boost::hash<std::wstring>()(L"folder.jpg");
                size_t thumb_key_2 = boost::hash<std::wstring>()(L"folder.jpeg");

                auto thumb_iterator_1 = dir_entry.find(thumb_key_1);
                auto thumb_iterator_2 = dir_entry.find(thumb_key_2);
                if (thumb_iterator_1 != dir_entry.cend())
                {
                    thumb_data = thumb_iterator_1->second.contents();
                }
                else if (thumb_iterator_2 != dir_entry.cend())
                {
                    thumb_data = thumb_iterator_2->second.contents();
                }
                else
                {
                    // No existing thumbnail - get one
                    if (dir_entry.size() > 0)
                    {
                        file_entry_type const & file_entry = dir_entry.cbegin()->second;
                        auto archive_key = file_entry.get_key();
                        auto image = get_image(session_id, key, archive_key, 0);
                        if (image.empty() == false)
                        {
                            mangapp::image img(image);
                            img.resize(128, 180);
                            thumb_data = img.contents(".jpeg");
                        }
                    }
                }
            }

            return thumb_data;
        }

        /**
        *   Gets the details of a manga/comic
        *
        *   @param key the key of the manga.comic
        *   @param on_event a function object that will be called on success or failure
        */
        void get_details(key_type key, std::function<void(mstch::map&&, bool)> on_event)
        {
            // Is the key valid?
            auto const manga_comic_iterator = library::find(key);
            if (manga_comic_iterator != library::cend())
            {
                // Yes, proceed
                search_online_source(manga_comic_iterator->second, on_event);
            }
        }

        /**
        *   Gets the desired image from an archive.
        *
        *   @param key the key of the manga
        *   @param key the key of the archive file
        *   @param index the index of the image
        *   @return a string containing the image's contents
        */
        std::string get_image(std::string const & session_id, key_type key, key_type file_key, size_t index) const
        {
            std::string image_contents;

            // Is the manga key valid?
            auto const manga_comic_iterator = library::find(key);
            if (manga_comic_iterator != library::cend())
            {
                size_t path_key = boost::hash<std::wstring>()(manga_comic_iterator->second.get_path());
                if (m_users.can_access(session_id, path_key) == false)
                    return "";

                // Yes. Is the file archive key valid?
                auto archive_iterator = manga_comic_iterator->second.find(file_key);
                if (archive_iterator != manga_comic_iterator->second.cend())
                {
                    auto file_path = archive_iterator->second.get_path() + archive_iterator->second.get_name();

                    auto archive_ptr = mangapp::archive::open(file_path);
                    // Make sure we have a valid archive pointer before proceeding
                    if (archive_ptr != nullptr)
                    {
                        // Remove any file entries that are not images
                        archive_ptr->filter([key](mangapp::archive::entry_pointer const & entry_ptr) -> bool
                        {
                            bool remove = is_image_extension(entry_ptr->extension()) == false || entry_ptr->is_dir() == true;

                            return remove;
                        });

                        // Get the contents of the image
                        if (archive_ptr->count() > 0)
                        {
                            auto const & image_ptr = (*archive_ptr)[index];

                            if (image_ptr != nullptr)
                                image_contents = image_ptr->contents();
                        }
                    }
                }
            }

            return image_contents;
        }
    protected:
        virtual void search_online_source(directory_entry_type & entry, std::function<void(mstch::map&&, bool)> on_event)
        {
        }
    private:
        library_map_type m_entries;
        mangapp::users & m_users;
    };
}

#endif
<commit_msg>Sort archive images in library::get_image<commit_after>#ifndef MANGAPP_LIBRARY_HPP
#define MANGAPP_LIBRARY_HPP

#include "archive.hpp"
#include "directory_entry.hpp"
#include "file_enumeration.hpp"
#include "sort.hpp"
#include "users.hpp"
#include "utf8.hpp"
#include "image.hpp"

#include <unordered_map>

#include <json11/json11.hpp>

#include <mstch/mstch.hpp>

namespace base
{
    namespace
    {
        std::vector<std::wstring> utf8_paths_to_utf16(std::vector<std::string> const & library_paths)
        {
            std::vector<std::wstring> utf16_paths;

            for (auto const & path : library_paths)
            {
                std::wstring utf16_str = to_utf16(path);

                utf16_paths.push_back(utf16_str);
            }

            return utf16_paths;
        }

        std::vector<std::wstring> json_to_utf16_vector(json11::Json const & library_paths)
        {
            std::vector<std::wstring> utf16_paths;

            for (auto const & element : library_paths.array_items())
            {
                json11::Json const & object = element.object_items();
                std::string utf8_str(object["path"].string_value());
                std::wstring utf16_str = to_utf16(utf8_str);

                utf16_paths.emplace_back(utf16_str);
            }

            return utf16_paths;
        }
    }

    template<class DirectoryEntryType>
    class library
    {
    public:
        typedef size_t key_type;
        typedef DirectoryEntryType directory_entry_type;
        typedef typename DirectoryEntryType::file_entry_type file_entry_type;

        typedef std::unordered_map<key_type, directory_entry_type> library_map_type;
        typedef typename library_map_type::iterator iterator;
        typedef typename library_map_type::const_iterator const_iterator;

        /**
        *  Constructor for the library. Multiple paths can be parsed.
        *
        *  @param library_paths a vector containing the file path(s)
        */
        library(std::vector<std::wstring> const & library_paths, mangapp::users & users) :
            m_entries(),
            m_users(users)
        {
            // Iterate through the libraries
            for (auto const & library_path : library_paths)
            {
                enumerate_files(library_path, file_search_flags::FlagDirectory, false,
                    [this](std::wstring const & path, file_search_flags flag)
                {
                    auto path_end_pos = path.rfind(L"/");

                    std::wstring name_str = path.substr(path_end_pos + 1);
                    std::wstring path_str(path, 0, path_end_pos + 1);

                    auto key = boost::hash<std::wstring>()(name_str);
                    m_entries.emplace(key, directory_entry_type(path_str, name_str, key));
                });
            }
        }

        library(std::vector<std::string> const & library_paths, mangapp::users & users) :
            library(utf8_paths_to_utf16(library_paths), users)
        {
        }

        library(json11::Json const & library_paths, mangapp::users & users) :
            library(json_to_utf16_vector(library_paths), users)
        {
        }

        virtual ~library()
        {
        }

        iterator begin()
        {
            return m_entries.begin();
        }

        iterator end()
        {
            return m_entries.end();
        }

        const_iterator cbegin() const
        {
            return m_entries.cbegin();
        }

        const_iterator cend() const
        {
            return m_entries.cend();
        }

        iterator find(key_type key)
        {
            return m_entries.find(key);
        }

        const_iterator find(key_type key) const
        {
            return m_entries.find(key);
        }

        key_type size() const
        {
            return m_entries.size();
        }

        mstch::map const get_list_context(std::string const & session_id) const
        {
            mstch::array library_array;

            // Enumerate all the entries the user can access
            std::vector<std::reference_wrapper<directory_entry_type const>> ordered;
            for (auto const & pair : m_entries)
            {
                size_t path_key = boost::hash<std::wstring>()(pair.second.get_path());
                if (m_users.can_access(session_id, path_key) == true)
                    ordered.push_back(std::cref(pair.second));
            }

            // Collate the entries
            std::sort(ordered.begin(), ordered.end(),
                [](std::reference_wrapper<directory_entry_type const> const & left,
                   std::reference_wrapper<directory_entry_type const> const & right) -> bool
            {
                return std::locale()(left.get().get_name(), right.get().get_name());
            });

            // Construct the array of manga/comics
            for (auto const & entry : ordered)
            {
                std::wstring utf16_name(entry.get().get_name());
                std::string utf8_name = to_utf8(utf16_name);

                library_array.emplace_back(mstch::map{
                    { "key",  std::to_string(entry.get().get_key()) },
                    { "name", utf8_name }
                });
            }

            return mstch::map({
                { "library-list", library_array }
            });
        }

        mstch::map get_files_context(std::string const & session_id, key_type key) const
        {
            auto const manga_comic_iterator = library::find(key);
            if (manga_comic_iterator != library::cend())
            {
                // Firstly, ensure the user has access
                size_t path_key = boost::hash<std::wstring>()(manga_comic_iterator->second.get_path());
                if (m_users.can_access(session_id, path_key) == false)
                    return mstch::map();

                // Enumerate all the files from the directory_entry
                std::vector<std::reference_wrapper<library::file_entry_type const>> ordered;

                std::for_each(manga_comic_iterator->second.cbegin(), manga_comic_iterator->second.cend(),
                    [&ordered](typename library::directory_entry_type::map_type::value_type const & entry)
                {
                    ordered.push_back(std::cref(entry.second));
                });

                // Sort the filenames based on a regex rule
                std::sort(ordered.begin(), ordered.end(),
                    [](std::reference_wrapper<library::file_entry_type const> const & left,
                       std::reference_wrapper<library::file_entry_type const> const & right)
                {
                    return sort::numerical_wregex_less()(left.get().get_name(), right.get().get_name());
                });

                mstch::array files_array{};

                // Construct and populate the array of files
                std::for_each(ordered.cbegin(), ordered.cend(),
                    [&files_array, key](std::reference_wrapper<library::file_entry_type const> const & value) -> void
                {
                    auto const & entry = value.get();

                    // Filter out any files that are not archives
                    if (is_archive_extension(entry.get_extension()) == true)
                    {
                        std::wstring const & utf16_name(entry.get_name());
                        std::string utf8_name = to_utf8(utf16_name);

                        files_array.emplace_back(mstch::map({
                            { "key", std::to_string(key) },
                            { "file-key", std::to_string(entry.get_key()) },
                            { "file-name", utf8_name }
                        }));
                    }
                });

                std::wstring const & utf16_name(manga_comic_iterator->second.get_name());
                std::string utf8_name = to_utf8(utf16_name);

                return mstch::map({
                    { "key", std::to_string(key) },
                    { "name", std::move(utf8_name) },
                    { "file-count", std::to_string(files_array.size()) },
                    { "files-list", std::move(files_array) },
                });
            }

            return mstch::map();
        }

        mstch::map const get_reader_context(std::string const & session_id, key_type key, key_type file_key) const
        {
            auto const entry_iterator = find(key);
            if (entry_iterator != cend())
            {
                // Ensure the user has access
                size_t path_key = boost::hash<std::wstring>()(entry_iterator->second.get_path());
                if (m_users.can_access(session_id, path_key) == false)
                    return mstch::map();

                // Find the requested archive based from its key
                auto archive_iterator = entry_iterator->second.find(file_key);
                // Was it found?
                if (archive_iterator != entry_iterator->second.cend())
                {
                    // Yes, get its path and open the archive
                    auto file_path = archive_iterator->second.get_path() + archive_iterator->second.get_name();
                    auto archive_ptr = mangapp::archive::open(file_path);
                    // Ensure we have a valid pointer
                    if (archive_ptr != nullptr)
                    {
                        mstch::array image_array;
                        mstch::array image_dropdown;
                        uint32_t image_count = 0;

                        // Populate the array of images
                        for (auto const & image_entry : *archive_ptr)
                        {
                            // Filter out any files that are not images
                            if (is_image_extension(image_entry->extension()) == true)
                            {
                                image_array.emplace_back(mstch::map({
                                    { "key", std::to_string(key) },
                                    { "file-key", std::to_string(file_key) },
                                    { "index", std::to_string(image_count) }
                                }));

                                image_dropdown.emplace_back(mstch::map({
                                    { "image-index", std::to_string(++image_count) }
                                }));
                            }
                        }

                        std::wstring const & utf16_name(entry_iterator->second.get_name());
                        std::string utf8_name = to_utf8(utf16_name);

                        return mstch::map({
                            { "name", utf8_name },
                            { "image-count", std::to_string(image_count) },
                            { "image-dropdown", image_dropdown },
                            { "image-list", image_array }
                        });
                    }
                }
            }

            return mstch::map();
        }

        /**
        *   Reads the thumbnail of a manga/comic from its folder or from an archive.
        *   Retrieval from an archive is NOT implemented yet.
        *
        *   @param key the key of the manga/comic
        *   @param index index of the archive in the folder
        *   @return a string containing the thumbnail's contents
        */
        std::string get_thumbnail(std::string const & session_id, key_type key, uint32_t index = 0) const
        {
            std::string thumb_data;

            auto const manga_comic_iterator = find(key);
            // Does the specified key exist in our map?
            if (manga_comic_iterator != cend())
            {
                // Look for an existing thumbnail
                directory_entry_type const & dir_entry = manga_comic_iterator->second;
                size_t thumb_key_1 = boost::hash<std::wstring>()(L"folder.jpg");
                size_t thumb_key_2 = boost::hash<std::wstring>()(L"folder.jpeg");

                auto thumb_iterator_1 = dir_entry.find(thumb_key_1);
                auto thumb_iterator_2 = dir_entry.find(thumb_key_2);
                if (thumb_iterator_1 != dir_entry.cend())
                {
                    thumb_data = thumb_iterator_1->second.contents();
                }
                else if (thumb_iterator_2 != dir_entry.cend())
                {
                    thumb_data = thumb_iterator_2->second.contents();
                }
                else
                {
                    // No existing thumbnail - get one
                    if (dir_entry.size() > 0)
                    {
                        file_entry_type const & file_entry = dir_entry.cbegin()->second;
                        auto archive_key = file_entry.get_key();
                        auto image = get_image(session_id, key, archive_key, 0);
                        if (image.empty() == false)
                        {
                            mangapp::image img(image);
                            img.resize(128, 180);
                            thumb_data = img.contents(".jpeg");
                        }
                    }
                }
            }

            return thumb_data;
        }

        /**
        *   Gets the details of a manga/comic
        *
        *   @param key the key of the manga.comic
        *   @param on_event a function object that will be called on success or failure
        */
        void get_details(key_type key, std::function<void(mstch::map&&, bool)> on_event)
        {
            // Is the key valid?
            auto const manga_comic_iterator = library::find(key);
            if (manga_comic_iterator != library::cend())
            {
                // Yes, proceed
                search_online_source(manga_comic_iterator->second, on_event);
            }
        }

        /**
        *   Gets the desired image from an archive.
        *
        *   @param key the key of the manga
        *   @param key the key of the archive file
        *   @param index the index of the image
        *   @return a string containing the image's contents
        */
        std::string get_image(std::string const & session_id, key_type key, key_type file_key, size_t index) const
        {
            std::string image_contents;

            // Is the manga key valid?
            auto const manga_comic_iterator = library::find(key);
            if (manga_comic_iterator != library::cend())
            {
                size_t path_key = boost::hash<std::wstring>()(manga_comic_iterator->second.get_path());
                if (m_users.can_access(session_id, path_key) == false)
                    return "";

                // Yes. Is the file archive key valid?
                auto archive_iterator = manga_comic_iterator->second.find(file_key);
                if (archive_iterator != manga_comic_iterator->second.cend())
                {
                    auto file_path = archive_iterator->second.get_path() + archive_iterator->second.get_name();

                    auto archive_ptr = mangapp::archive::open(file_path);
                    // Make sure we have a valid archive pointer before proceeding
                    if (archive_ptr != nullptr)
                    {
                        // Remove any file entries that are not images
                        archive_ptr->filter([key](mangapp::archive::entry_pointer const & entry_ptr) -> bool
                        {
                            bool remove = is_image_extension(entry_ptr->extension()) == false || entry_ptr->is_dir() == true;

                            return remove;
                        });

                        // Sort them
                        std::sort(archive_ptr->begin(), archive_ptr->end(),
                            [](mangapp::archive::entry_pointer const & left_ptr,
                               mangapp::archive::entry_pointer const & right_ptr) -> int
                        {
                            return std::locale()(left_ptr->name(), right_ptr->name());
                        });

                        // Get the contents of the image
                        if (archive_ptr->count() > 0)
                        {
                            auto const & image_ptr = (*archive_ptr)[index];

                            if (image_ptr != nullptr)
                                image_contents = image_ptr->contents();
                        }
                    }
                }
            }

            return image_contents;
        }
    protected:
        virtual void search_online_source(directory_entry_type & entry, std::function<void(mstch::map&&, bool)> on_event)
        {
        }
    private:
        library_map_type m_entries;
        mangapp::users & m_users;
    };
}

#endif
<|endoftext|>


<commit_before>/************************************************************************
    filename:   FalStaticText.cpp
    created:    Tue Jul 5 2005
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "FalStaticText.h"
#include "falagard/CEGUIFalWidgetLookManager.h"
#include "falagard/CEGUIFalWidgetLookFeel.h"
#include "CEGUIWindowManager.h"
#include "elements/CEGUIScrollbar.h"

// Start of CEGUI namespace section
namespace CEGUI
{
    const utf8 FalagardStaticText::WidgetTypeName[] = "Falagard/StaticText";

    /************************************************************************
        Properties
    *************************************************************************/
    FalagardStaticTextProperties::TextColours       FalagardStaticText::d_textColoursProperty;
    FalagardStaticTextProperties::VertFormatting    FalagardStaticText::d_vertFormattingProperty;
    FalagardStaticTextProperties::HorzFormatting    FalagardStaticText::d_horzFormattingProperty;
    FalagardStaticTextProperties::VertScrollbar     FalagardStaticText::d_vertScrollbarProperty;
    FalagardStaticTextProperties::HorzScrollbar     FalagardStaticText::d_horzScrollbarProperty;

    /************************************************************************
        Constructor
    *************************************************************************/
    FalagardStaticText::FalagardStaticText(const String& type, const String& name) :
        FalagardStatic(type, name),
        d_horzFormatting(LeftAligned),
        d_vertFormatting(VertCentred),
        d_textCols(0xFFFFFFFF),
        d_enableVertScrollbar(false),
        d_enableHorzScrollbar(false)
    {
        addProperty(&d_textColoursProperty);
        addProperty(&d_vertFormattingProperty);
        addProperty(&d_horzFormattingProperty);
        addProperty(&d_vertScrollbarProperty);
        addProperty(&d_horzScrollbarProperty);
    }

    /************************************************************************
        Deconstructor
    *************************************************************************/
    FalagardStaticText::~FalagardStaticText()
    {
    }

    /*************************************************************************
        Perform initialisation for the widget.
    *************************************************************************/
    void FalagardStaticText::initialise(void)
    {
        FalagardStatic::initialise();

        // do initial scrollbar setup
        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();

        vertScrollbar->hide();
        horzScrollbar->hide();

        addChildWindow(vertScrollbar);
        addChildWindow(horzScrollbar);

        performChildWindowLayout();

        // event subscription
        vertScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&FalagardStaticText::handleScrollbarChange, this));
        horzScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&FalagardStaticText::handleScrollbarChange, this));
    }

    /************************************************************************
        Populates the rendercache with imagery for this widget
    *************************************************************************/
    void FalagardStaticText::populateRenderCache()
    {
        // base class rendering
        FalagardStatic::populateRenderCache();

        // text rendering
        renderScrolledText();
    }

    /************************************************************************
        Caches the text according to scrollbar positions
    *************************************************************************/
    void FalagardStaticText::renderScrolledText()
    {
        const Font* font = getFont();
        // can't render text without a font :)
        if (font == 0)
            return;

        // get destination area for the text.
        Rect absarea(getTextRenderArea());
        Rect clipper(absarea);

        float textHeight = font->getFormattedLineCount(d_text, absarea, (TextFormatting)d_horzFormatting) * font->getLineSpacing();

        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();

        // see if we may need to adjust horizontal position
        if (horzScrollbar->isVisible())
        {
            switch(d_horzFormatting)
            {
            case LeftAligned:
            case WordWrapLeftAligned:
            case Justified:
            case WordWrapJustified:
                absarea.offset(Point(-horzScrollbar->getScrollPosition(), 0));
                break;

            case Centred:
            case WordWrapCentred:
                absarea.setWidth(horzScrollbar->getDocumentSize());
                absarea.offset(Point(-horzScrollbar->getScrollPosition(), 0));
                break;

            case RightAligned:
            case WordWrapRightAligned:
                absarea.offset(Point(horzScrollbar->getScrollPosition(), 0));
                break;
            }

        }

        // adjust y positioning according to formatting option
        switch(d_vertFormatting)
        {
        case TopAligned:
            absarea.d_top -= vertScrollbar->getScrollPosition();
            break;

        case VertCentred:
            // if scroll bar is in use, act like TopAligned
            if (vertScrollbar->isVisible())
            {
                absarea.d_top -= vertScrollbar->getScrollPosition();
            }
            // no scroll bar, so centre text instead.
            else
            {
                absarea.d_top += PixelAligned((absarea.getHeight() - textHeight) * 0.5f);
            }

            break;

        case BottomAligned:
            absarea.d_top = absarea.d_bottom - textHeight;
            absarea.d_top += vertScrollbar->getScrollPosition();
            break;
        }

        // calculate final colours
        ColourRect final_cols(d_textCols);
        final_cols.modulateAlpha(getEffectiveAlpha());
        // cache the text for rendering.
        d_renderCache.cacheText(d_text, font, (TextFormatting)d_horzFormatting, absarea, 0, final_cols, &clipper);
    }

    /************************************************************************
        Returns the vertical scrollbar component
    *************************************************************************/
    Scrollbar* FalagardStaticText::getVertScrollbar(void) const
    {
        // return component created by look'n'feel assignment.
        return static_cast<Scrollbar*>(WindowManager::getSingleton().getWindow(getName() + "__auto_vscrollbar__"));
    }

    /************************************************************************
        Returns the horizontal scrollbar component
    *************************************************************************/
    Scrollbar* FalagardStaticText::getHorzScrollbar(void) const
    {
        // return component created by look'n'feel assignment.
        return static_cast<Scrollbar*>(WindowManager::getSingleton().getWindow(getName() + "__auto_hscrollbar__"));
    }

    /************************************************************************
        Gets the text rendering area
    *************************************************************************/
    Rect FalagardStaticText::getTextRenderArea(void) const
    {
        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();
        bool v_visible = vertScrollbar->isVisible(true);
        bool h_visible = horzScrollbar->isVisible(true);

        // get WidgetLookFeel for the assigned look.
        const WidgetLookFeel& wlf = WidgetLookManager::getSingleton().getWidgetLook(d_lookName);

        // if either of the scrollbars are visible, we might want to use a special rendering area
        if (v_visible || h_visible)
        {
            String area_name(d_frameEnabled ? "WithFrameTextRenderArea" : "NoFrameTextRenderArea");

            if (h_visible)
            {
                area_name += "H";
            }
            if (v_visible)
            {
                area_name += "V";
            }
            area_name += "Scroll";

            if (wlf.isNamedAreaDefined(area_name))
            {
                return wlf.getNamedArea(area_name).getArea().getPixelRect(*this);
            }
        }

        // default to plain WithFrameTextRenderArea
        return wlf.getNamedArea("WithFrameTextRenderArea").getArea().getPixelRect(*this);
    }

    /************************************************************************
        Gets the pixel size of the document
    *************************************************************************/
    Size FalagardStaticText::getDocumentSize(const Rect& renderArea) const
    {
        // we need a font to really measure anything
        const Font* font = getFont();
        if (font==0)
        {
            return Size(0,0);
        }
        // return the total extent of the text
        float totalHeight = font->getFormattedLineCount(d_text, renderArea, (TextFormatting)d_horzFormatting) * font->getLineSpacing();
        float widestItem  = font->getFormattedTextExtent(d_text, renderArea, (TextFormatting)d_horzFormatting);
        return Size(widestItem,totalHeight);
    }

    /*************************************************************************
        Sets the colours to be applied when rendering the text.
    *************************************************************************/
    void FalagardStaticText::setTextColours(const ColourRect& colours)
    {
        d_textCols = colours;
        requestRedraw();
    }

    /*************************************************************************
        Set the formatting required for the text.
    *************************************************************************/
    void FalagardStaticText::setVerticalFormatting(VertFormatting v_fmt)
    {
        d_vertFormatting = v_fmt;
        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Set the formatting required for the text.
    *************************************************************************/
    void FalagardStaticText::setHorizontalFormatting(HorzFormatting h_fmt)
    {
        d_horzFormatting = h_fmt;
        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Set whether the vertical scroll bar will be shown if needed.
    *************************************************************************/
    void FalagardStaticText::setVerticalScrollbarEnabled(bool setting)
    {
        d_enableVertScrollbar = setting;
        configureScrollbars();
        performChildWindowLayout();
    }

    /*************************************************************************
        Set whether the horizontal scroll bar will be shown if needed.
    *************************************************************************/
    void FalagardStaticText::setHorizontalScrollbarEnabled(bool setting)
    {
        d_enableHorzScrollbar = setting;
        configureScrollbars();
        performChildWindowLayout();
    }

    /*************************************************************************
        display required integrated scroll bars according to current state
        of the edit box and update their values.
    *************************************************************************/
    void FalagardStaticText::configureScrollbars(void)
    {
        // get the scrollbars
        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();

        // get the sizes we need
        Rect renderArea(getTextRenderArea());
        Size renderAreaSize(renderArea.getSize());
        Size documentSize(getDocumentSize(renderArea));

        // show or hide vertical scroll bar as required (or as specified by option)
        bool showVert = ((documentSize.d_height > renderAreaSize.d_height) && d_enableVertScrollbar);
        bool showHorz = ((documentSize.d_width > renderAreaSize.d_width) && d_enableHorzScrollbar);
        // show or hide vertical scroll bar
        if (showVert)
        {
            vertScrollbar->show();
        }
        else
        {
            vertScrollbar->hide();
        }

        // show or hide horizontal scroll bar
        if (showHorz)
        {
            horzScrollbar->show();
        }
        else
        {
            horzScrollbar->hide();
        }

        // if scrollbar visibility just changed we have might have a better TextRenderArea
        // if so we go with that instead
        Rect updatedRenderArea = getTextRenderArea();
        if (renderArea!=updatedRenderArea)
        {
            renderArea = updatedRenderArea;
            renderAreaSize = renderArea.getSize();
        }

        // Set up scroll bar values
        vertScrollbar->setDocumentSize(documentSize.d_height);
        vertScrollbar->setPageSize(renderAreaSize.d_height);
        vertScrollbar->setStepSize(ceguimax(1.0f, renderAreaSize.d_height / 10.0f));

        horzScrollbar->setDocumentSize(documentSize.d_width);
        horzScrollbar->setPageSize(renderAreaSize.d_width);
        horzScrollbar->setStepSize(ceguimax(1.0f, renderAreaSize.d_width / 10.0f));
    }

    /*************************************************************************
        Handler called when text is changed.
    *************************************************************************/
    void FalagardStaticText::onTextChanged(WindowEventArgs& e)
    {
        FalagardStatic::onTextChanged(e);

        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Handler called when size is changed
    *************************************************************************/
    void FalagardStaticText::onSized(WindowEventArgs& e)
    {
        FalagardStatic::onSized(e);

        configureScrollbars();
    }

    /*************************************************************************
        Handler called when font is changed.
    *************************************************************************/
    void FalagardStaticText::onFontChanged(WindowEventArgs& e)
    {
        FalagardStatic::onFontChanged(e);

        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Handler for mouse wheel changes
    *************************************************************************/
    void FalagardStaticText::onMouseWheel(MouseEventArgs& e)
    {
        // base class processing.
        FalagardStatic::onMouseWheel(e);

        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();
        if (vertScrollbar->isVisible() && (vertScrollbar->getDocumentSize() > vertScrollbar->getPageSize()))
        {
            vertScrollbar->setScrollPosition(vertScrollbar->getScrollPosition() + vertScrollbar->getStepSize() * -e.wheelChange);
        }
        else if (horzScrollbar->isVisible() && (horzScrollbar->getDocumentSize() > horzScrollbar->getPageSize()))
        {
            horzScrollbar->setScrollPosition(horzScrollbar->getScrollPosition() + horzScrollbar->getStepSize() * -e.wheelChange);
        }

        e.handled = true;
    }

    /*************************************************************************
        Handler called when the scroll bar positions change
    *************************************************************************/
    bool FalagardStaticText::handleScrollbarChange(const EventArgs& e)
    {
        requestRedraw();
        return true;
    }

    //////////////////////////////////////////////////////////////////////////
    /*************************************************************************

        Factory Methods

    *************************************************************************/
    //////////////////////////////////////////////////////////////////////////
    Window* FalagardStaticTextFactory::createWindow(const String& name)
    {
        return new FalagardStaticText(d_type, name);
    }

    void FalagardStaticTextFactory::destroyWindow(Window* window)
    {
        delete window;
    }

} // End of  CEGUI namespace section
<commit_msg>Fixed case in StaticText where default text area was always used if frame was disabled.<commit_after>/************************************************************************
    filename:   FalStaticText.cpp
    created:    Tue Jul 5 2005
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "FalStaticText.h"
#include "falagard/CEGUIFalWidgetLookManager.h"
#include "falagard/CEGUIFalWidgetLookFeel.h"
#include "CEGUIWindowManager.h"
#include "elements/CEGUIScrollbar.h"

// Start of CEGUI namespace section
namespace CEGUI
{
    const utf8 FalagardStaticText::WidgetTypeName[] = "Falagard/StaticText";

    /************************************************************************
        Properties
    *************************************************************************/
    FalagardStaticTextProperties::TextColours       FalagardStaticText::d_textColoursProperty;
    FalagardStaticTextProperties::VertFormatting    FalagardStaticText::d_vertFormattingProperty;
    FalagardStaticTextProperties::HorzFormatting    FalagardStaticText::d_horzFormattingProperty;
    FalagardStaticTextProperties::VertScrollbar     FalagardStaticText::d_vertScrollbarProperty;
    FalagardStaticTextProperties::HorzScrollbar     FalagardStaticText::d_horzScrollbarProperty;

    /************************************************************************
        Constructor
    *************************************************************************/
    FalagardStaticText::FalagardStaticText(const String& type, const String& name) :
        FalagardStatic(type, name),
        d_horzFormatting(LeftAligned),
        d_vertFormatting(VertCentred),
        d_textCols(0xFFFFFFFF),
        d_enableVertScrollbar(false),
        d_enableHorzScrollbar(false)
    {
        addProperty(&d_textColoursProperty);
        addProperty(&d_vertFormattingProperty);
        addProperty(&d_horzFormattingProperty);
        addProperty(&d_vertScrollbarProperty);
        addProperty(&d_horzScrollbarProperty);
    }

    /************************************************************************
        Deconstructor
    *************************************************************************/
    FalagardStaticText::~FalagardStaticText()
    {
    }

    /*************************************************************************
        Perform initialisation for the widget.
    *************************************************************************/
    void FalagardStaticText::initialise(void)
    {
        FalagardStatic::initialise();

        // do initial scrollbar setup
        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();

        vertScrollbar->hide();
        horzScrollbar->hide();

        addChildWindow(vertScrollbar);
        addChildWindow(horzScrollbar);

        performChildWindowLayout();

        // event subscription
        vertScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&FalagardStaticText::handleScrollbarChange, this));
        horzScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&FalagardStaticText::handleScrollbarChange, this));
    }

    /************************************************************************
        Populates the rendercache with imagery for this widget
    *************************************************************************/
    void FalagardStaticText::populateRenderCache()
    {
        // base class rendering
        FalagardStatic::populateRenderCache();

        // text rendering
        renderScrolledText();
    }

    /************************************************************************
        Caches the text according to scrollbar positions
    *************************************************************************/
    void FalagardStaticText::renderScrolledText()
    {
        const Font* font = getFont();
        // can't render text without a font :)
        if (font == 0)
            return;

        // get destination area for the text.
        Rect absarea(getTextRenderArea());
        Rect clipper(absarea);

        float textHeight = font->getFormattedLineCount(d_text, absarea, (TextFormatting)d_horzFormatting) * font->getLineSpacing();

        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();

        // see if we may need to adjust horizontal position
        if (horzScrollbar->isVisible())
        {
            switch(d_horzFormatting)
            {
            case LeftAligned:
            case WordWrapLeftAligned:
            case Justified:
            case WordWrapJustified:
                absarea.offset(Point(-horzScrollbar->getScrollPosition(), 0));
                break;

            case Centred:
            case WordWrapCentred:
                absarea.setWidth(horzScrollbar->getDocumentSize());
                absarea.offset(Point(-horzScrollbar->getScrollPosition(), 0));
                break;

            case RightAligned:
            case WordWrapRightAligned:
                absarea.offset(Point(horzScrollbar->getScrollPosition(), 0));
                break;
            }

        }

        // adjust y positioning according to formatting option
        switch(d_vertFormatting)
        {
        case TopAligned:
            absarea.d_top -= vertScrollbar->getScrollPosition();
            break;

        case VertCentred:
            // if scroll bar is in use, act like TopAligned
            if (vertScrollbar->isVisible())
            {
                absarea.d_top -= vertScrollbar->getScrollPosition();
            }
            // no scroll bar, so centre text instead.
            else
            {
                absarea.d_top += PixelAligned((absarea.getHeight() - textHeight) * 0.5f);
            }

            break;

        case BottomAligned:
            absarea.d_top = absarea.d_bottom - textHeight;
            absarea.d_top += vertScrollbar->getScrollPosition();
            break;
        }

        // calculate final colours
        ColourRect final_cols(d_textCols);
        final_cols.modulateAlpha(getEffectiveAlpha());
        // cache the text for rendering.
        d_renderCache.cacheText(d_text, font, (TextFormatting)d_horzFormatting, absarea, 0, final_cols, &clipper);
    }

    /************************************************************************
        Returns the vertical scrollbar component
    *************************************************************************/
    Scrollbar* FalagardStaticText::getVertScrollbar(void) const
    {
        // return component created by look'n'feel assignment.
        return static_cast<Scrollbar*>(WindowManager::getSingleton().getWindow(getName() + "__auto_vscrollbar__"));
    }

    /************************************************************************
        Returns the horizontal scrollbar component
    *************************************************************************/
    Scrollbar* FalagardStaticText::getHorzScrollbar(void) const
    {
        // return component created by look'n'feel assignment.
        return static_cast<Scrollbar*>(WindowManager::getSingleton().getWindow(getName() + "__auto_hscrollbar__"));
    }

    /************************************************************************
        Gets the text rendering area
    *************************************************************************/
    Rect FalagardStaticText::getTextRenderArea(void) const
    {
        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();
        bool v_visible = vertScrollbar->isVisible(true);
        bool h_visible = horzScrollbar->isVisible(true);

        // get WidgetLookFeel for the assigned look.
        const WidgetLookFeel& wlf = WidgetLookManager::getSingleton().getWidgetLook(d_lookName);

        String area_name(d_frameEnabled ? "WithFrameTextRenderArea" : "NoFrameTextRenderArea");

        // if either of the scrollbars are visible, we might want to use a special rendering area
        if (v_visible || h_visible)
        {
            if (h_visible)
            {
                area_name += "H";
            }
            if (v_visible)
            {
                area_name += "V";
            }
            area_name += "Scroll";
        }

        if (wlf.isNamedAreaDefined(area_name))
        {
            return wlf.getNamedArea(area_name).getArea().getPixelRect(*this);
        }

        // default to plain WithFrameTextRenderArea
        return wlf.getNamedArea("WithFrameTextRenderArea").getArea().getPixelRect(*this);
    }

    /************************************************************************
        Gets the pixel size of the document
    *************************************************************************/
    Size FalagardStaticText::getDocumentSize(const Rect& renderArea) const
    {
        // we need a font to really measure anything
        const Font* font = getFont();
        if (font==0)
        {
            return Size(0,0);
        }
        // return the total extent of the text
        float totalHeight = font->getFormattedLineCount(d_text, renderArea, (TextFormatting)d_horzFormatting) * font->getLineSpacing();
        float widestItem  = font->getFormattedTextExtent(d_text, renderArea, (TextFormatting)d_horzFormatting);
        return Size(widestItem,totalHeight);
    }

    /*************************************************************************
        Sets the colours to be applied when rendering the text.
    *************************************************************************/
    void FalagardStaticText::setTextColours(const ColourRect& colours)
    {
        d_textCols = colours;
        requestRedraw();
    }

    /*************************************************************************
        Set the formatting required for the text.
    *************************************************************************/
    void FalagardStaticText::setVerticalFormatting(VertFormatting v_fmt)
    {
        d_vertFormatting = v_fmt;
        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Set the formatting required for the text.
    *************************************************************************/
    void FalagardStaticText::setHorizontalFormatting(HorzFormatting h_fmt)
    {
        d_horzFormatting = h_fmt;
        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Set whether the vertical scroll bar will be shown if needed.
    *************************************************************************/
    void FalagardStaticText::setVerticalScrollbarEnabled(bool setting)
    {
        d_enableVertScrollbar = setting;
        configureScrollbars();
        performChildWindowLayout();
    }

    /*************************************************************************
        Set whether the horizontal scroll bar will be shown if needed.
    *************************************************************************/
    void FalagardStaticText::setHorizontalScrollbarEnabled(bool setting)
    {
        d_enableHorzScrollbar = setting;
        configureScrollbars();
        performChildWindowLayout();
    }

    /*************************************************************************
        display required integrated scroll bars according to current state
        of the edit box and update their values.
    *************************************************************************/
    void FalagardStaticText::configureScrollbars(void)
    {
        // get the scrollbars
        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();

        // get the sizes we need
        Rect renderArea(getTextRenderArea());
        Size renderAreaSize(renderArea.getSize());
        Size documentSize(getDocumentSize(renderArea));

        // show or hide vertical scroll bar as required (or as specified by option)
        bool showVert = ((documentSize.d_height > renderAreaSize.d_height) && d_enableVertScrollbar);
        bool showHorz = ((documentSize.d_width > renderAreaSize.d_width) && d_enableHorzScrollbar);
        // show or hide vertical scroll bar
        if (showVert)
        {
            vertScrollbar->show();
        }
        else
        {
            vertScrollbar->hide();
        }

        // show or hide horizontal scroll bar
        if (showHorz)
        {
            horzScrollbar->show();
        }
        else
        {
            horzScrollbar->hide();
        }

        // if scrollbar visibility just changed we have might have a better TextRenderArea
        // if so we go with that instead
        Rect updatedRenderArea = getTextRenderArea();
        if (renderArea!=updatedRenderArea)
        {
            renderArea = updatedRenderArea;
            renderAreaSize = renderArea.getSize();
        }

        // Set up scroll bar values
        vertScrollbar->setDocumentSize(documentSize.d_height);
        vertScrollbar->setPageSize(renderAreaSize.d_height);
        vertScrollbar->setStepSize(ceguimax(1.0f, renderAreaSize.d_height / 10.0f));

        horzScrollbar->setDocumentSize(documentSize.d_width);
        horzScrollbar->setPageSize(renderAreaSize.d_width);
        horzScrollbar->setStepSize(ceguimax(1.0f, renderAreaSize.d_width / 10.0f));
    }

    /*************************************************************************
        Handler called when text is changed.
    *************************************************************************/
    void FalagardStaticText::onTextChanged(WindowEventArgs& e)
    {
        FalagardStatic::onTextChanged(e);

        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Handler called when size is changed
    *************************************************************************/
    void FalagardStaticText::onSized(WindowEventArgs& e)
    {
        FalagardStatic::onSized(e);

        configureScrollbars();
    }

    /*************************************************************************
        Handler called when font is changed.
    *************************************************************************/
    void FalagardStaticText::onFontChanged(WindowEventArgs& e)
    {
        FalagardStatic::onFontChanged(e);

        configureScrollbars();
        requestRedraw();
    }

    /*************************************************************************
        Handler for mouse wheel changes
    *************************************************************************/
    void FalagardStaticText::onMouseWheel(MouseEventArgs& e)
    {
        // base class processing.
        FalagardStatic::onMouseWheel(e);

        Scrollbar* vertScrollbar = getVertScrollbar();
        Scrollbar* horzScrollbar = getHorzScrollbar();
        if (vertScrollbar->isVisible() && (vertScrollbar->getDocumentSize() > vertScrollbar->getPageSize()))
        {
            vertScrollbar->setScrollPosition(vertScrollbar->getScrollPosition() + vertScrollbar->getStepSize() * -e.wheelChange);
        }
        else if (horzScrollbar->isVisible() && (horzScrollbar->getDocumentSize() > horzScrollbar->getPageSize()))
        {
            horzScrollbar->setScrollPosition(horzScrollbar->getScrollPosition() + horzScrollbar->getStepSize() * -e.wheelChange);
        }

        e.handled = true;
    }

    /*************************************************************************
        Handler called when the scroll bar positions change
    *************************************************************************/
    bool FalagardStaticText::handleScrollbarChange(const EventArgs& e)
    {
        requestRedraw();
        return true;
    }

    //////////////////////////////////////////////////////////////////////////
    /*************************************************************************

        Factory Methods

    *************************************************************************/
    //////////////////////////////////////////////////////////////////////////
    Window* FalagardStaticTextFactory::createWindow(const String& name)
    {
        return new FalagardStaticText(d_type, name);
    }

    void FalagardStaticTextFactory::destroyWindow(Window* window)
    {
        delete window;
    }

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2021 Morwenn
 * SPDX-License-Identifier: MIT
 */
#include <numeric>
#include <type_traits>
#include <vector>
#include <catch2/catch.hpp>
#include <cpp-sort/probes.h>

//
// Common tests for measures of presortedness
//

TEMPLATE_TEST_CASE( "test every probe with all_equal distribution", "[probe]",
                    decltype(cppsort::probe::block),
                    decltype(cppsort::probe::dis),
                    decltype(cppsort::probe::enc),
                    decltype(cppsort::probe::exc),
                    decltype(cppsort::probe::ham),
                    decltype(cppsort::probe::inv),
                    decltype(cppsort::probe::max),
                    decltype(cppsort::probe::mono),
                    decltype(cppsort::probe::osc),
                    decltype(cppsort::probe::rem),
                    decltype(cppsort::probe::runs),
                    decltype(cppsort::probe::sus) )
{
    // Ensure that all measures of presortedness return 0 when
    // given a collection where all elements are equal

    std::vector<int> collection(50, 5);
    std::decay_t<TestType> mop;
    auto presortedness = mop(collection);
    CHECK( presortedness == 0 );
}

TEMPLATE_TEST_CASE( "test every probe with a sorted collection", "[probe]",
                    decltype(cppsort::probe::block),
                    decltype(cppsort::probe::dis),
                    decltype(cppsort::probe::enc),
                    decltype(cppsort::probe::exc),
                    decltype(cppsort::probe::ham),
                    decltype(cppsort::probe::inv),
                    decltype(cppsort::probe::max),
                    decltype(cppsort::probe::mono),
                    decltype(cppsort::probe::osc),
                    decltype(cppsort::probe::rem),
                    decltype(cppsort::probe::runs),
                    decltype(cppsort::probe::sus) )
{
    // Ensure that all measures of presortedness return 0 when
    // given a collection where all elements are sorted

    std::vector<int> collection(50);
    std::iota(collection.begin(), collection.end(), 0);
    std::decay_t<TestType> mop;
    auto presortedness = mop(collection);
    CHECK( presortedness == 0 );
}
<commit_msg>Test MOPs with collections of 0~or 1 elements<commit_after>/*
 * Copyright (c) 2021 Morwenn
 * SPDX-License-Identifier: MIT
 */
#include <numeric>
#include <type_traits>
#include <vector>
#include <catch2/catch.hpp>
#include <cpp-sort/probes.h>

//
// Common tests for measures of presortedness
//

TEMPLATE_TEST_CASE( "test every probe with all_equal distribution", "[probe]",
                    decltype(cppsort::probe::block),
                    decltype(cppsort::probe::dis),
                    decltype(cppsort::probe::enc),
                    decltype(cppsort::probe::exc),
                    decltype(cppsort::probe::ham),
                    decltype(cppsort::probe::inv),
                    decltype(cppsort::probe::max),
                    decltype(cppsort::probe::mono),
                    decltype(cppsort::probe::osc),
                    decltype(cppsort::probe::rem),
                    decltype(cppsort::probe::runs),
                    decltype(cppsort::probe::sus) )
{
    // Ensure that all measures of presortedness return 0 when
    // given a collection where all elements are equal

    std::vector<int> collection(50, 5);
    std::decay_t<TestType> mop;
    auto presortedness = mop(collection);
    CHECK( presortedness == 0 );
}

TEMPLATE_TEST_CASE( "test every probe with a sorted collection", "[probe]",
                    decltype(cppsort::probe::block),
                    decltype(cppsort::probe::dis),
                    decltype(cppsort::probe::enc),
                    decltype(cppsort::probe::exc),
                    decltype(cppsort::probe::ham),
                    decltype(cppsort::probe::inv),
                    decltype(cppsort::probe::max),
                    decltype(cppsort::probe::mono),
                    decltype(cppsort::probe::osc),
                    decltype(cppsort::probe::rem),
                    decltype(cppsort::probe::runs),
                    decltype(cppsort::probe::sus) )
{
    // Ensure that all measures of presortedness return 0 when
    // given a collection where all elements are sorted

    std::vector<int> collection(50);
    std::iota(collection.begin(), collection.end(), 0);
    std::decay_t<TestType> mop;
    auto presortedness = mop(collection);
    CHECK( presortedness == 0 );
}

TEMPLATE_TEST_CASE( "test every probe with a 0 or 1 element", "[probe]",
                    decltype(cppsort::probe::block),
                    decltype(cppsort::probe::dis),
                    decltype(cppsort::probe::enc),
                    decltype(cppsort::probe::exc),
                    decltype(cppsort::probe::ham),
                    decltype(cppsort::probe::inv),
                    decltype(cppsort::probe::max),
                    decltype(cppsort::probe::mono),
                    decltype(cppsort::probe::osc),
                    decltype(cppsort::probe::rem),
                    decltype(cppsort::probe::runs),
                    decltype(cppsort::probe::sus) )
{
    // Ensure that all measures of presortedness return 0 when
    // given a collection with 0 or 1 element

    std::decay_t<TestType> mop;

    SECTION( "empty collection" )
    {
        std::vector<int> collection;
        auto presortedness = mop(collection);
        CHECK( presortedness == 0 );
    }

    SECTION( "one-element collection" )
    {
        std::vector<int> collection = { 42 };
        auto presortedness = mop(collection);
        CHECK( presortedness == 0 );
    }
}
<|endoftext|>


<commit_before><commit_msg>Changed color of magma in bossfight<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2009-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <test/fuzz/fuzz.h>

#include <cstdint>
#include <unistd.h>
#include <vector>

static bool read_stdin(std::vector<uint8_t>& data)
{
    uint8_t buffer[1024];
    ssize_t length = 0;
    while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
        data.insert(data.end(), buffer, buffer + length);

        if (data.size() > (1 << 20)) return false;
    }
    return length == 0;
}

// Default initialization: Override using a non-weak initialize().
__attribute__((weak)) void initialize()
{
}

// This function is used by libFuzzer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    const std::vector<uint8_t> input(data, data + size);
    test_one_input(input);
    return 0;
}

// This function is used by libFuzzer
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
{
    initialize();
    return 0;
}

// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
// the main(...) function.
__attribute__((weak))
#endif
int
main(int argc, char** argv)
{
    initialize();
#ifdef __AFL_INIT
    // Enable AFL deferred forkserver mode. Requires compilation using
    // afl-clang-fast++. See fuzzing.md for details.
    __AFL_INIT();
#endif

#ifdef __AFL_LOOP
    // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
    // See fuzzing.md for details.
    while (__AFL_LOOP(1000)) {
        std::vector<uint8_t> buffer;
        if (!read_stdin(buffer)) {
            continue;
        }
        test_one_input(buffer);
    }
#else
    std::vector<uint8_t> buffer;
    if (!read_stdin(buffer)) {
        return 0;
    }
    test_one_input(buffer);
#endif
    return 0;
}
<commit_msg>tests: Remove Cygwin WinMain workaround<commit_after>// Copyright (c) 2009-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <test/fuzz/fuzz.h>

#include <cstdint>
#include <unistd.h>
#include <vector>

static bool read_stdin(std::vector<uint8_t>& data)
{
    uint8_t buffer[1024];
    ssize_t length = 0;
    while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
        data.insert(data.end(), buffer, buffer + length);

        if (data.size() > (1 << 20)) return false;
    }
    return length == 0;
}

// Default initialization: Override using a non-weak initialize().
__attribute__((weak)) void initialize()
{
}

// This function is used by libFuzzer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    const std::vector<uint8_t> input(data, data + size);
    test_one_input(input);
    return 0;
}

// This function is used by libFuzzer
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
{
    initialize();
    return 0;
}

// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
// the main(...) function.
__attribute__((weak)) int main(int argc, char** argv)
{
    initialize();
#ifdef __AFL_INIT
    // Enable AFL deferred forkserver mode. Requires compilation using
    // afl-clang-fast++. See fuzzing.md for details.
    __AFL_INIT();
#endif

#ifdef __AFL_LOOP
    // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
    // See fuzzing.md for details.
    while (__AFL_LOOP(1000)) {
        std::vector<uint8_t> buffer;
        if (!read_stdin(buffer)) {
            continue;
        }
        test_one_input(buffer);
    }
#else
    std::vector<uint8_t> buffer;
    if (!read_stdin(buffer)) {
        return 0;
    }
    test_one_input(buffer);
#endif
    return 0;
}
<|endoftext|>


<commit_before>#include <cinttypes>
#include <cstring>
#include <cstdio>
#include <iostream>

#include "mem/Pem.hpp"
#include "med/MedCommon.hpp"
#include "med/MedException.hpp"

Pem::Pem(size_t size, MemIO* memio) : Mem(size) {
  this->memio = memio;
}

Pem::Pem(Address addr, size_t size, MemIO* memio) : Mem(size) {
  this->memio = memio;
  setAddress(addr);
}

string Pem::bytesToString(Byte* buf, const string& scanType) {
  char str[MAX_STRING_SIZE + 1];
  switch (stringToScanType(scanType)) {
  case Int8:
    sprintf(str, "%" PRIu8, *(uint8_t*)buf);
    break;
  case Int16:
    sprintf(str, "%" PRIu16, *(uint16_t*)buf);
    break;
  case Int32:
    sprintf(str, "%" PRIu32, *(uint32_t*)buf);
    break;
  case Float32:
    sprintf(str, "%f", *(float*)buf);
    break;
  case Float64:
    sprintf(str, "%lf", *(double*)buf);
    break;
  case String:
    sprintf(str, "%s", buf);
    break;
  case Unknown:
    throw_with_nested(MedException(string("bytesToString: Error Type: ") + scanType));
  }
  return string(str);
}

string Pem::getValue(const string& scanType) {
  MemPtr pem = memio->read(address, size);
  Byte* buf = pem->getData();
  return Pem::bytesToString(buf, scanType);
}

string Pem::getValue() {
  string scanType = getScanType();
  MemPtr pem = memio->read(address, size);
  Byte* buf = pem->getData();
  return Pem::bytesToString(buf, scanType);
}

string Pem::getScanType() {
  return scanTypeToString(scanType);
}

tuple<Byte*, size_t> Pem::stringToBytes(const string& value, const string& scanType) {
  int size = scanTypeToSize(stringToScanType(scanType));
  vector<string> tokens = ScanParser::getValues(value);
  Byte* buf = new Byte[size * tokens.size()];

  Byte* ptr = buf;
  for (size_t i = 0; i < tokens.size(); i++) {
    stringToMemory(tokens[i], stringToScanType(scanType), ptr);
    ptr += size;
  }
  return make_tuple(buf, size * tokens.size()); // delete
}

void Pem::setValue(const string& value, const string& scanType) {
  auto buffer = Pem::stringToBytes(value, scanType);
  Byte* bytes = std::get<0>(buffer);
  int size = std::get<1>(buffer);

  MemPtr mem = MemPtr(new Mem(size));
  mem->setAddress(address);
  memcpy(mem->getData(), bytes, size);
  delete[] bytes;

  memio->write(address, mem, size);
}

void Pem::setScanType(const string& scanType) {
  this->scanType = stringToScanType(scanType);
}

MemIO* Pem::getMemIO() {
  return memio;
}
<commit_msg>Fix scan string<commit_after>#include <cinttypes>
#include <cstring>
#include <cstdio>
#include <iostream>

#include "mem/Pem.hpp"
#include "med/MedCommon.hpp"
#include "med/MedException.hpp"

Pem::Pem(size_t size, MemIO* memio) : Mem(size) {
  this->memio = memio;
}

Pem::Pem(Address addr, size_t size, MemIO* memio) : Mem(size) {
  this->memio = memio;
  setAddress(addr);
}

string Pem::bytesToString(Byte* buf, const string& scanType) {
  char str[MAX_STRING_SIZE + 1];
  switch (stringToScanType(scanType)) {
  case Int8:
    sprintf(str, "%" PRIu8, *(uint8_t*)buf);
    break;
  case Int16:
    sprintf(str, "%" PRIu16, *(uint16_t*)buf);
    break;
  case Int32:
    sprintf(str, "%" PRIu32, *(uint32_t*)buf);
    break;
  case Float32:
    sprintf(str, "%f", *(float*)buf);
    break;
  case Float64:
    sprintf(str, "%lf", *(double*)buf);
    break;
  case String:
    sprintf(str, "%s", buf);
    break;
  case Unknown:
    throw_with_nested(MedException(string("bytesToString: Error Type: ") + scanType));
  }
  return string(str);
}

string Pem::getValue(const string& scanType) {
  MemPtr pem = memio->read(address, size);
  Byte* buf = pem->getData();
  return Pem::bytesToString(buf, scanType);
}

string Pem::getValue() {
  string scanType = getScanType();
  MemPtr pem = memio->read(address, size);
  Byte* buf = pem->getData();
  return Pem::bytesToString(buf, scanType);
}

string Pem::getScanType() {
  return scanTypeToString(scanType);
}

tuple<Byte*, size_t> Pem::stringToBytes(const string& value, const string& scanType) {
  int size = scanTypeToSize(stringToScanType(scanType));
  vector<string> tokens = ScanParser::getValues(value);
  Byte* buf = new Byte[size * tokens.size()];

  Byte* ptr = buf;
  for (size_t i = 0; i < tokens.size(); i++) {
    stringToMemory(tokens[i], stringToScanType(scanType), ptr);
    ptr += size;
  }
  return make_tuple(buf, size * tokens.size()); // delete
}

void Pem::setValue(const string& value, const string& scanType) {
  auto buffer = Pem::stringToBytes(value, scanType);
  Byte* bytes = std::get<0>(buffer);
  int size = std::get<1>(buffer);

  MemPtr mem = MemPtr(new Mem(size));
  mem->setAddress(address);
  memcpy(mem->getData(), bytes, size);
  delete[] bytes;

  memio->write(address, mem, size);
}

void Pem::setScanType(const string& scanType) {
  this->scanType = stringToScanType(scanType);
  size_t newSize;
  Byte* newData;
  Byte* temp;

  if (this->scanType == ScanType::String) {
    newSize = MAX_STRING_SIZE;
    newData = new Byte[newSize];
  }
  else {
    newSize = scanTypeToSize(this->scanType);
    newData = new Byte[newSize];
  }

  temp = data;
  data = newData;
  size = newSize;
  delete[] temp;
}

MemIO* Pem::getMemIO() {
  return memio;
}
<|endoftext|>