From e788c575125a1adb37ae935656f50988447be9cb Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 13 Jul 2015 04:57:01 +0800 Subject: [PATCH] add some missing files, refactor group --- include/nana/gui/widgets/group.hpp | 18 +- source/gui/widgets/group.cpp | 99 +++++--- source/paint/detail/image_bmp.hpp | 371 +++++++++++++++++++++++++++++ source/paint/detail/image_ico.hpp | 43 ++++ source/paint/detail/image_png.hpp | 188 +++++++++++++++ 5 files changed, 674 insertions(+), 45 deletions(-) create mode 100644 source/paint/detail/image_bmp.hpp create mode 100644 source/paint/detail/image_ico.hpp create mode 100644 source/paint/detail/image_png.hpp diff --git a/include/nana/gui/widgets/group.hpp b/include/nana/gui/widgets/group.hpp index 19cb6dce..26a0e408 100644 --- a/include/nana/gui/widgets/group.hpp +++ b/include/nana/gui/widgets/group.hpp @@ -18,10 +18,7 @@ #define NANA_GUI_WIDGETS_GROUP_HPP #include -#include #include -#include -#include namespace nana{ class group @@ -29,19 +26,26 @@ namespace nana{ { place plc_outer{*this}; panel content {*this}; - label titel/* {*this}*/; place plc_inner{content}; - unsigned int gap; + + struct implement; public: group( window parent, ///< - string titel_ ={STR("")}, ///< + std::wstring titel_ ={STR("")}, ///< bool format =false, ///< Use a formated label? unsigned gap =2, ///< betwen the content and the external limit rectangle r ={} ///< ); + + ~group(); + place& plc (){ return plc_inner; } window inner(){ return content; } - label& lbl (){ return titel; } + private: + ::nana::string _m_caption() const override; + void _m_caption(::nana::string&&) override; + private: + std::unique_ptr impl_; }; }//end namespace nana diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index b4905afe..e18f0bbd 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -9,55 +9,78 @@ * * @file: nana/gui/widgets/group.cpp * - * @contributors: Stefan Pfeifer (st-321), Jinhao, Ariel Vina-Rodriguez (qPCR4vir) + * @Author: Stefan Pfeifer(st-321), Ariel Vina-Rodriguez (qPCR4vir) * * @brief group is a widget used to visually group and layout other widgets. */ #include +#include +#include namespace nana{ - group::group( window parent, ///< - string titel_ /*={}*/, ///< - bool format /*=false*/, ///< - unsigned gap /*=2*/, ///< - rectangle r /*={} */ ///< + + struct group::implement + { + label caption; + }; + + group::group( window parent, ///< + std::wstring titel_ /*={}*/, ///< + bool format /*=false*/, ///< + unsigned gap /*=2*/, ///< + rectangle r /*={} */ ///< ) - : panel (parent, r), - titel (*this, titel_) - { - titel.format(format); - ::nana::size sz = titel.measure(1000); - std::stringstream ft; + : panel (parent, r), + impl_(new implement) + { + impl_->caption.create(*this); + impl_->caption.format(format); + ::nana::size sz = impl_->caption.measure(1000); + std::stringstream ft; + + ft << "vert margin=[0," << gap << "," << gap << "," << gap << "]" + << " >" + << " "; + plc_outer.div(ft.str().c_str()); + + plc_outer["titel" ] << impl_->caption; + plc_outer["content"] << content; + plc_outer.collocate(); + + color pbg = API::bgcolor( parent); + impl_->caption.bgcolor(pbg.blend(colors::black, 0.975) ); + color bg=pbg.blend(colors::black, 0.950 ); + + bgcolor(pbg); + content.bgcolor(bg); + + drawing dw(*this); + + // This drawing function is owner by the onwer of dw (the outer panel of the group widget), not by dw !! + dw.draw([gap, sz, bg, pbg](paint::graphics& graph) + { + graph.rectangle(true, pbg); + graph.round_rectangle(rectangle(point(gap - 1, sz.height / 2), + nana::size(graph.width() - 2 * (gap - 1), graph.height() - sz.height / 2 - (gap - 1)) + ), + 3, 3, colors::gray_border, true, bg); + }); + } - ft << "vertical margin=[0," << gap << "," << gap << "," << gap << "]" - << " >" - << " "; - plc_outer.div(ft.str().c_str()); + group::~group() + { + } - plc_outer["titel" ] << titel; - plc_outer["content"] << content; - plc_outer.collocate(); - - color pbg = API::bgcolor( parent); - titel.bgcolor(pbg.blend(colors::black, 0.975) ); - color bg=pbg.blend(colors::black, 0.950 ); - bgcolor(pbg); - content.bgcolor(bg); - - drawing dw(*this); - - // This drawing function is owner by the onwer of dw (the outer panel of the group widget), not by dw !! - dw.draw([gap,sz,bg,pbg](paint::graphics& graph) - { - graph.rectangle(true, pbg); - graph.round_rectangle(rectangle( point ( gap-1 , sz.height/2 ), - nana::size (graph.width()-2*(gap-1), graph.height()-sz.height/2-(gap-1)) - ), - 3,3, colors::gray_border, true, bg); - }); - } + ::nana::string group::_m_caption() const + { + return impl_->caption.caption(); + } + void group::_m_caption(::nana::string&& str) + { + return impl_->caption.caption(std::move(str)); + } }//end namespace nana diff --git a/source/paint/detail/image_bmp.hpp b/source/paint/detail/image_bmp.hpp new file mode 100644 index 00000000..77f87df2 --- /dev/null +++ b/source/paint/detail/image_bmp.hpp @@ -0,0 +1,371 @@ +/* + * Bitmap Format Graphics Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/detail/image_bmp.hpp + * @contributors: Ryan Gonzalez + */ +#ifndef NANA_PAINT_DETAIL_IMAGE_BMP_HPP +#define NANA_PAINT_DETAIL_IMAGE_BMP_HPP + +#include +#include + +namespace nana{ namespace paint +{ + namespace detail + { + +#ifndef NANA_WINDOWS + struct bitmap_file_header + { + unsigned short bfType; + unsigned long bfSize; + unsigned short bfReserved1; + unsigned short bfReserved2; + unsigned long bfOffBits; + } __attribute__((packed)); + + struct bitmap_info_header { + unsigned long biSize; + long biWidth; + long biHeight; + unsigned short biPlanes; + unsigned short biBitCount; + unsigned long biCompression; + unsigned long biSizeImage; + long biXPelsPerMeter; + long biYPelsPerMeter; + unsigned long biClrUsed; + unsigned long biClrImportant; + }__attribute__((packed)); + + struct rgb_quad + { + unsigned char rgbBlue; + unsigned char rgbGreen; + 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 RGBQUAD rgb_quad; +#endif + + class image_bmp + :public image::image_impl_interface + { + public: + image_bmp(){} + + ~image_bmp() + { + this->close(); + } + + bool open(const nana::char_t* filename) override + { + if(nullptr == filename) return false; + std::ifstream ifs; +#if defined(NANA_UNICODE) + ifs.open(static_cast(nana::charset(filename)).c_str(), std::ios::binary); +#else + ifs.open(filename, std::ios::binary); +#endif + if(ifs) + { + ifs.seekg(0, std::ios::end); + auto size = ifs.tellg(); + ifs.seekg(0, std::ios::beg); + + 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 == ifs.gcount()) + { + bitmap_file_header * header = reinterpret_cast(buffer.get()); + if((header->bfType == 0x4D42) && (static_cast(header->bfSize) == size)) + { + unsigned char* bits = reinterpret_cast(buffer.get() + header->bfOffBits); + bitmap_info * info = reinterpret_cast(header + 1); + + //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); + 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) + { + rgb_quad & 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) + { + rgb_quad & 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) + { + rgb_quad & 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) + { + rgb_quad & 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 + rgb_quad& 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 + rgb_quad& 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) + rgb_quad & 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)); + rgb_quad & 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; + } + } + } + } + } + } + return (false == pixbuf_.empty()); + } + + bool alpha_channel() const override + { + return false; + } + + bool empty() const override + { + return pixbuf_.empty(); + } + + void close() override + { + pixbuf_.close(); + } + + nana::size size() const override + { + return pixbuf_.size(); + } + + void paste(const nana::rectangle& src_r, graph_reference graph, const point& p_dst) const override + { + if(graph && pixbuf_) + pixbuf_.paste(src_r, graph.handle(), p_dst); + } + + void stretch(const nana::rectangle& src_r, graph_reference graph, const nana::rectangle& r) const override + { + if(graph && pixbuf_) + pixbuf_.stretch(src_r, graph.handle(), r); + } + private: + nana::paint::pixel_buffer pixbuf_; + };//end class bmpfile + }//end namespace detail +}//end namespace paint +}//end namespace nana + +#endif diff --git a/source/paint/detail/image_ico.hpp b/source/paint/detail/image_ico.hpp new file mode 100644 index 00000000..37226431 --- /dev/null +++ b/source/paint/detail/image_ico.hpp @@ -0,0 +1,43 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_ICO_HPP +#define NANA_PAINT_DETAIL_IMAGE_ICO_HPP + +#include + +namespace nana{ namespace paint +{ + namespace detail + { + class image_ico + :public image::image_impl_interface + { +#if defined(NANA_WINDOWS) + struct handle_deleter + { + void operator()(HICON* handle) const; + };//end struct handle_deleter + typedef std::shared_ptr ptr_t; +#else + typedef std::shared_ptr ptr_t; +#endif + public: + image_ico(bool is_ico); + + bool open(const nana::char_t* filename) override; + bool alpha_channel() const override; + bool empty() const override; + void close() override; + nana::size size() const override; + virtual void paste(const nana::rectangle& src_r, graph_reference graph, const point& p_dst) const override; + virtual void stretch(const nana::rectangle&, graph_reference graph, const nana::rectangle& r) const override; + + const ptr_t & ptr() const; + private: + const bool is_ico_; + nana::size size_; + ptr_t ptr_; + };//end class image_ico + } +}//end namespace paint +}//end namespace nana + +#endif diff --git a/source/paint/detail/image_png.hpp b/source/paint/detail/image_png.hpp new file mode 100644 index 00000000..cab432cd --- /dev/null +++ b/source/paint/detail/image_png.hpp @@ -0,0 +1,188 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_PNG_HPP +#define NANA_PAINT_DETAIL_IMAGE_PNG_HPP + +#include + +//Separate the libpng from the package that system provides. +#if defined(NANA_LIBPNG) + #include +#else + #include +#endif + +#include +#include + +namespace nana +{ + namespace paint{ namespace detail{ + + class image_png + : public image::image_impl_interface + { + public: + image_png() + { + } + + bool open(const nana::char_t* png_file) override + { +#ifdef NANA_UNICODE + FILE * fp = ::fopen(static_cast(nana::charset(png_file)).c_str(), "rb"); +#else + FILE* fp = ::fopen(png_file, "rb"); +#endif + if(nullptr == fp) return false; + + bool is_opened = false; + + png_byte png_sig[8]; + ::fread(png_sig, 1, 8, fp); + + //Test whether the file is a png. + if(0 == png_sig_cmp(png_sig, 0, 8)) + { + png_structp png_ptr = ::png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if(png_ptr) + { + png_infop info_ptr = ::png_create_info_struct(png_ptr); + + if(info_ptr) + { + if(!setjmp(png_jmpbuf(png_ptr))) + { + //The following codes may longjmp while init_io error. + ::png_init_io(png_ptr, fp); + ::png_set_sig_bytes(png_ptr, 8); + ::png_read_info(png_ptr, info_ptr); + + const int png_width = ::png_get_image_width(png_ptr, info_ptr); + const int png_height = ::png_get_image_height(png_ptr, info_ptr); + png_byte color_type = ::png_get_color_type(png_ptr, info_ptr); + + ::png_set_interlace_handling(png_ptr); + ::png_read_update_info(png_ptr, info_ptr); + + //The following codes may longjmp while image_read error. + png_bytep * row_ptrs = new png_bytep[png_height]; + const std::size_t png_rowbytes = ::png_get_rowbytes(png_ptr, info_ptr); + + pixbuf_.open(png_width, png_height); + + const bool is_alpha_enabled = ((PNG_COLOR_MASK_ALPHA & color_type) != 0); + pixbuf_.alpha_channel(is_alpha_enabled); + + if(is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_argb_t))) + { + for(int i = 0; i < png_height; ++i) + row_ptrs[i] = reinterpret_cast(pixbuf_.raw_ptr(i)); + + ::png_read_image(png_ptr, row_ptrs); + ::png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + + for (int i = 0; i < png_height; ++i) + { + auto p = pixbuf_.raw_ptr(i); + for (int u = 0; u < png_width; ++u) + { + auto t = p[u].element.red; + p[u].element.red = p[u].element.blue; + p[u].element.blue = t; + } + } + } + else + { + png_byte * png_pixbuf = new png_byte[png_height * png_rowbytes]; + + for(int i = 0; i < png_height; ++i) + row_ptrs[i] = reinterpret_cast(png_pixbuf + png_rowbytes * i); + + ::png_read_image(png_ptr, row_ptrs); + ::png_destroy_read_struct(&png_ptr, &info_ptr, 0); + + std::size_t png_pixel_bytes = png_rowbytes / png_width; + + pixel_argb_t * rgb_row_ptr = pixbuf_.raw_ptr(0); + for(int y = 0; y < png_height; ++y) + { + png_bytep png_ptr = row_ptrs[y]; + + pixel_argb_t * rgb_end = rgb_row_ptr + png_width; + + if(is_alpha_enabled) + { + for(pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i) + { + i->element.red = png_ptr[0]; + i->element.green = png_ptr[1]; + i->element.blue = png_ptr[2]; + i->element.alpha_channel = png_ptr[3]; + png_ptr += png_pixel_bytes; + } + } + else + { + for(pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i) + { + i->element.red = png_ptr[0]; + i->element.green = png_ptr[1]; + i->element.blue = png_ptr[2]; + i->element.alpha_channel = 255; + png_ptr += png_pixel_bytes; + } + } + rgb_row_ptr = rgb_end; + } + + delete [] png_pixbuf; + } + delete [] row_ptrs; + is_opened = true; + } + } + } + } + + ::fclose(fp); + return is_opened; + } + + bool alpha_channel() const override + { + return pixbuf_.alpha_channel(); + } + + virtual bool empty() const override + { + return pixbuf_.empty(); + } + + virtual void close() override + { + pixbuf_.close(); + } + + virtual nana::size size() const override + { + return pixbuf_.size(); + } + + void paste(const nana::rectangle& src_r, graph_reference graph, const point& p_dst) const override + { + pixbuf_.paste(src_r, graph.handle(), p_dst); + } + + void stretch(const nana::rectangle& src_r, graph_reference dst, const nana::rectangle& r) const override + { + pixbuf_.stretch(src_r, dst.handle(), r); + } + private: + nana::paint::pixel_buffer pixbuf_; + + }; + }//end namespace detail + }//end namespace paint +}//end namespace nana + +#endif