diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 8e0e7b44..693310a2 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -1,7 +1,7 @@ /** * A Menu implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2009-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -48,6 +48,8 @@ namespace nana item_proxy& checked(bool); bool checked() const; + std::string text() const; + std::size_t index() const; private: std::size_t index_; @@ -123,8 +125,19 @@ namespace nana ~menu(); /// Appends an item to the menu. - item_proxy append(std::string text_utf8, const event_fn_t& callback= event_fn_t()); + item_proxy append(std::string text_utf8, const event_fn_t& handler = {}); void append_splitter(); + + /// Inserts new item at specified position + /** + * It will invalidate the existing item proxies from the specified position. + * @param pos The position where new item to be inserted + * @param text_utf8 The title of item + * @param handler The event handler for the item. + * @return the item proxy to the new inserted item. + */ + item_proxy insert(std::size_t pos, std::string text_utf8, const event_fn_t& handler = {}); + void clear(); ///< Erases all of the items. /// Closes the menu. It does not destroy the menu; just close the window for the menu. void close(); diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 745a52a2..4613ca7a 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -845,7 +845,7 @@ namespace nana { namespace experimental { namespace filesystem GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); if (get_file_size_ex) { - HANDLE handle = ::CreateFile(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + HANDLE handle = ::CreateFile(p.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (INVALID_HANDLE_VALUE != handle) { LARGE_INTEGER li; diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 1decffd5..02ba5649 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1,7 +1,7 @@ /* * A Menu implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2009-2016 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -86,6 +86,11 @@ namespace nana return item_.flags.checked; } + std::string menu_item_type::item_proxy::text() const + { + return item_.text; + } + std::size_t menu_item_type::item_proxy::index() const { return index_; @@ -1117,10 +1122,11 @@ namespace nana delete impl_; } - auto menu::append(std::string text_utf8, const menu::event_fn_t& callback) -> item_proxy + auto menu::append(std::string text_utf8, const menu::event_fn_t& handler) -> item_proxy { - impl_->mbuilder.data().items.emplace_back(new item_type(std::move(text_utf8), callback)); - return item_proxy(size() - 1, *impl_->mbuilder.data().items.back()); + std::unique_ptr item{ new item_type{ std::move(text_utf8), handler } }; + impl_->mbuilder.data().items.emplace_back(item.get()); + return item_proxy(size() - 1, *item.release()); } void menu::append_splitter() @@ -1128,6 +1134,18 @@ namespace nana impl_->mbuilder.data().items.emplace_back(new item_type); } + auto menu::insert(std::size_t pos, std::string text_utf8, const event_fn_t& handler) -> item_proxy + { + auto & items = impl_->mbuilder.data().items; + if (pos > items.size()) + throw std::out_of_range("menu: a new item inserted to an invalid position"); + + std::unique_ptr item{ new item_type{ std::move(text_utf8), handler } }; + impl_->mbuilder.data().items.emplace(impl_->mbuilder.data().items.cbegin() + pos, item.get()); + + return item_proxy{ pos, *item.release() }; + } + void menu::clear() { internal_scope_guard lock; diff --git a/source/paint/detail/image_bmp.hpp b/source/paint/detail/image_bmp.hpp index 23d7907e..e3893c61 100644 --- a/source/paint/detail/image_bmp.hpp +++ b/source/paint/detail/image_bmp.hpp @@ -1,7 +1,7 @@ /* * Bitmap Format Graphics Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -30,6 +30,15 @@ namespace nana{ namespace paint unsigned bfOffBits; } __attribute__((packed)); + struct bitmap_core_header + { + unsigned biSize; + unsigned short biWidth; + unsigned short biHeight; + unsigned short biPlanes; + unsigned short biBitCount; + } __attribute__((packed)); + struct bitmap_info_header { unsigned biSize; int biWidth; @@ -51,15 +60,10 @@ namespace nana{ namespace paint unsigned char rgbRed; unsigned char rgbReserved; }; - - struct bitmap_info - { - bitmap_info_header bmiHeader; - rgb_quad bmiColors[1]; - }__attribute__((packed)); #else - typedef BITMAPFILEHEADER bitmap_file_header; - typedef BITMAPINFO bitmap_info; + typedef BITMAPFILEHEADER bitmap_file_header; + typedef BITMAPCOREHEADER bitmap_core_header; + typedef BITMAPINFOHEADER bitmap_info_header; typedef RGBQUAD rgb_quad; #endif @@ -67,244 +71,42 @@ namespace nana{ namespace paint :public basic_image_pixbuf { public: - image_bmp(){} - ~image_bmp() { this->close(); } - bool open(const void* data, std::size_t bytes) override + bool open(const void* file_data, std::size_t bytes) override { - auto bmp_data = reinterpret_cast(data); - - auto header = reinterpret_cast(bmp_data); - if ((header->bfType != 0x4D42) || (header->bfSize != bytes)) + auto bmp_file = reinterpret_cast(file_data); + if ((bmp_file->bfType != 0x4D42) || (bmp_file->bfSize != bytes)) return false; - auto bits = reinterpret_cast(bmp_data + header->bfOffBits); - auto info = reinterpret_cast(header + 1); + auto const header_bytes = *reinterpret_cast(bmp_file + 1); + + //There are two kind of base headers. Determinate it by size of header(The first ulong of header). + //Only Windows Bitmap(BITMAPINFOHEADER) is supported. + if (sizeof(bitmap_core_header) == header_bytes) + { + //The OS/2 BITMAPCOREHEADER is not supported. + throw std::invalid_argument("BMP with OS/2 BITMAPCOREHEADER is not supported now."); + } + + auto header = reinterpret_cast(bmp_file + 1); + + const std::size_t bmp_height = std::abs(header->biHeight); //Bitmap file is 4byte-aligned for each line. - std::size_t bytes_per_line; - const std::size_t height_pixels = std::abs(info->bmiHeader.biHeight); - if (0 == info->bmiHeader.biSizeImage) - bytes_per_line = (((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) & ~31) >> 3); + auto bytes_per_line = (((header->biWidth * header->biBitCount + 31) & ~31) >> 3); + + pixbuf_.open(header->biWidth, bmp_height); + + auto bits = reinterpret_cast(reinterpret_cast(file_data) + bmp_file->bfOffBits); + + if (16 <= header->biBitCount) + pixbuf_.put(bits, header->biWidth, bmp_height, header->biBitCount, bytes_per_line, (header->biHeight < 0)); else - bytes_per_line = info->bmiHeader.biSizeImage / height_pixels; - - pixbuf_.open(info->bmiHeader.biWidth, height_pixels); - - auto d = pixbuf_.raw_ptr(0); - - if (16 <= info->bmiHeader.biBitCount) - { - pixbuf_.put(bits, info->bmiHeader.biWidth, height_pixels, info->bmiHeader.biBitCount, bytes_per_line, (info->bmiHeader.biHeight < 0)); - } - else if (8 == info->bmiHeader.biBitCount) - { - const auto lend = d + info->bmiHeader.biWidth * height_pixels; - - if (info->bmiHeader.biHeight < 0) - { - auto s = bits; - while (d < lend) - { - auto d_p = d; - auto dpend = d_p + info->bmiHeader.biWidth; - auto s_p = s; - while (d_p != dpend) - { - auto & rgb = info->bmiColors[*s_p++]; - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - } - d = dpend; - s += bytes_per_line; - } - } - else - { - const auto* s = bits + bytes_per_line * (height_pixels - 1); - while (d < lend) - { - auto d_p = d; - auto* const dpend = d_p + info->bmiHeader.biWidth; - const auto * s_p = s; - while (d_p != dpend) - { - auto & rgb = info->bmiColors[*s_p++]; - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - } - d = dpend; - s -= bytes_per_line; - } - } - } - else if (4 == info->bmiHeader.biBitCount) - { - const auto * const lend = d + info->bmiHeader.biWidth * height_pixels; - if (info->bmiHeader.biHeight < 0) - { - const unsigned char* s = bits; - while (d < lend) - { - auto d_p = d; - auto * const dpend = d_p + info->bmiHeader.biWidth; - unsigned index = 0; - while (d_p != dpend) - { - auto & rgb = info->bmiColors[(index & 1) ? (s[index >> 1] & 0xF) : (s[index >> 1] & 0xF0) >> 4]; - - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - ++index; - } - d = dpend; - s += bytes_per_line; - } - } - else - { - const auto* s = bits + bytes_per_line * (height_pixels - 1); - while (d < lend) - { - auto d_p = d; - auto * const dpend = d_p + info->bmiHeader.biWidth; - - unsigned index = 0; - while (d_p != dpend) - { - auto & rgb = info->bmiColors[(index & 1) ? (s[index >> 1] & 0xF) : (s[index >> 1] & 0xF0) >> 4]; - - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - ++index; - } - d = dpend; - s -= bytes_per_line; - } - } - } - else if (2 == info->bmiHeader.biBitCount) - { - const auto * const lend = d + info->bmiHeader.biWidth * height_pixels; - if (info->bmiHeader.biHeight < 0) - { - const unsigned char* s = bits; - while (d < lend) - { - auto d_p = d; - auto * const dpend = d_p + info->bmiHeader.biWidth; - unsigned index = 0; - while (d_p != dpend) - { - unsigned shift = (3 - (index & 0x3)) << 1; // (index % 4) * 2 - auto& rgb = info->bmiColors[(s[index >> 2] & (0x3 << shift)) >> shift]; - - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - ++index; - } - d = dpend; - s += bytes_per_line; - } - } - else - { - const auto* s = bits + bytes_per_line * (height_pixels - 1); - while (d < lend) - { - auto d_p = d; - auto * const dpend = d_p + info->bmiHeader.biWidth; - - unsigned index = 0; - while (d_p != dpend) - { - unsigned shift = (3 - (index & 0x3)) << 1; // (index % 4) * 2 - auto& rgb = info->bmiColors[(s[index >> 2] & (0x3 << shift)) >> shift]; - - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - ++index; - } - d = dpend; - s -= bytes_per_line; - } - } - } - else if (1 == info->bmiHeader.biBitCount) - { - const auto * const lend = d + info->bmiHeader.biWidth * height_pixels; - if (info->bmiHeader.biHeight < 0) - { - const auto* s = bits; - while (d < lend) - { - auto d_p = d; - auto * const dpend = d_p + info->bmiHeader.biWidth; - unsigned index = 0; - while (d_p != dpend) - { - unsigned bi = (7 - (index & 7)); //(index % 8) - auto & rgb = info->bmiColors[(s[index >> 3] & (1 << bi)) >> bi]; - - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - ++index; - } - d = dpend; - s += bytes_per_line; - } - } - else - { - const auto* s = bits + bytes_per_line * (height_pixels - 1); - while (d < lend) - { - auto d_p = d; - auto * const dpend = d_p + info->bmiHeader.biWidth; - - unsigned index = 0; - while (d_p != dpend) - { - unsigned bi = (7 - (index & 7)); - auto & rgb = info->bmiColors[(s[index >> 3] & (1 << bi)) >> bi]; - - d_p->element.red = rgb.rgbRed; - d_p->element.green = rgb.rgbGreen; - d_p->element.blue = rgb.rgbBlue; - d_p->element.alpha_channel = rgb.rgbReserved; - ++d_p; - ++index; - } - d = dpend; - s -= bytes_per_line; - } - } - } + _m_put_with_palette(header, bits, bytes_per_line); return true; } @@ -312,20 +114,15 @@ namespace nana{ namespace paint bool open(const std::experimental::filesystem::path& filename) override { std::ifstream ifs(filename.string(), std::ios::binary); - if(ifs) + + auto const bytes = static_cast(std::experimental::filesystem::file_size(filename)); + if (ifs && (bytes > static_cast(sizeof(bitmap_file_header)))) { - ifs.seekg(0, std::ios::end); - auto size = static_cast(ifs.tellg()); - ifs.seekg(0, std::ios::beg); + std::unique_ptr buffer{ new char[bytes] }; - if(size <= static_cast(sizeof(bitmap_file_header))) - return false; - - std::unique_ptr buffer(new char[static_cast(size)]); - - ifs.read(buffer.get(), size); - if (size == static_cast(ifs.gcount())) - return open(buffer.get(), size); + ifs.read(buffer.get(), bytes); + if (bytes == static_cast(ifs.gcount())) + return open(buffer.get(), bytes); } return false; } @@ -334,6 +131,96 @@ namespace nana{ namespace paint { return false; } + private: + void _m_put_with_palette(const bitmap_info_header* header, const unsigned char* pixel_indexes, unsigned line_bytes) + { + auto const image_height = std::abs(header->biHeight); + const std::size_t total_pixels = header->biWidth * static_cast(image_height); + + auto const color_table = reinterpret_cast(reinterpret_cast(header) + header->biSize); + + auto dst_px = pixbuf_.raw_ptr(0); + auto const end_dst_px = dst_px + total_pixels; + + int line_pos = image_height - 1; + int delta = -1; + if (header->biHeight < 0) + { + line_pos = 0; + delta = 1; + } + + if (8 == header->biBitCount) + { + while (dst_px < end_dst_px) + { + auto px_indexes = pixel_indexes + line_bytes * line_pos; + auto const line_end_dst_px = dst_px + header->biWidth; + while (dst_px != line_end_dst_px) + { + auto & rgb = color_table[*px_indexes++]; + dst_px->element.red = rgb.rgbRed; + dst_px->element.green = rgb.rgbGreen; + dst_px->element.blue = rgb.rgbBlue; + dst_px->element.alpha_channel = rgb.rgbReserved; + + ++dst_px; + } + line_pos += delta; + } + } + else + { + while (dst_px < end_dst_px) + { + auto px_indexes = pixel_indexes + line_bytes * line_pos; + auto const line_end_dst_px = dst_px + header->biWidth; + std::size_t pos = 0; + switch (header->biBitCount) + { + case 4: + while (dst_px != line_end_dst_px) + { + auto & rgb = color_table[((pos & 1) ? px_indexes[pos >> 1] : (px_indexes[pos >> 1] >> 4)) & 0xF]; + dst_px->element.red = rgb.rgbRed; + dst_px->element.green = rgb.rgbGreen; + dst_px->element.blue = rgb.rgbBlue; + dst_px->element.alpha_channel = rgb.rgbReserved; + ++dst_px; + ++pos; + } + break; + case 2: + while (dst_px != line_end_dst_px) + { + //auto const shift = ((3 - (pos & 0x3)) << 1); // (index % 4) * 2 + auto& rgb = color_table[(px_indexes[pos >> 2] >> ((3 - (pos & 0x3)) << 1)) & 0x3]; + dst_px->element.red = rgb.rgbRed; + dst_px->element.green = rgb.rgbGreen; + dst_px->element.blue = rgb.rgbBlue; + dst_px->element.alpha_channel = rgb.rgbReserved; + ++dst_px; + ++pos; + } + break; + case 1: + while (dst_px != line_end_dst_px) + { + auto & rgb = color_table[(px_indexes[pos >> 3] >> (7 - (pos & 7))) & 1]; + + dst_px->element.red = rgb.rgbRed; + dst_px->element.green = rgb.rgbGreen; + dst_px->element.blue = rgb.rgbBlue; + dst_px->element.alpha_channel = rgb.rgbReserved; + ++dst_px; + ++pos; + } + break; + } + line_pos += delta; + } + } + } };//end class bmpfile }//end namespace detail }//end namespace paint