From d0a317bd45ea6155cc25b4cffe69cfef600c057a Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Thu, 11 Dec 2014 03:32:35 +0800 Subject: [PATCH] first init of 0.9 --- LICENSE_1_0.txt | 23 + build/codeblocks/nana.cbp | 121 + build/codeblocks/nana.depend | 539 +++ build/codeblocks/nana.layout | 154 + build/makefile/makefile | 42 + build/makefile/readme.txt | 31 + build/vc2013/nana.sln | 22 + build/vc2013/nana.v12.suo | Bin 0 -> 23552 bytes build/vc2013/nana.vcxproj | 166 + build/vc2013/nana.vcxproj.filters | 295 ++ extrlib/readme.txt | 1 + how-to-install.txt | 7 + include/nana/any.hpp | 145 + include/nana/audio/detail/audio_device.hpp | 53 + include/nana/audio/detail/audio_stream.hpp | 81 + .../nana/audio/detail/buffer_preparation.hpp | 65 + include/nana/audio/player.hpp | 25 + include/nana/basic_types.hpp | 254 ++ include/nana/charset.hpp | 67 + include/nana/concepts.hpp | 132 + include/nana/config.hpp | 62 + include/nana/datetime.hpp | 75 + include/nana/deploy.hpp | 67 + .../nana/detail/linux_X11/msg_dispatcher.hpp | 341 ++ include/nana/detail/linux_X11/msg_packet.hpp | 32 + .../nana/detail/linux_X11/platform_spec.hpp | 317 ++ include/nana/detail/win32/platform_spec.hpp | 179 + include/nana/exceptions.hpp | 95 + include/nana/extrlib/png.h | 2654 ++++++++++++ include/nana/extrlib/pngconf.h | 596 +++ include/nana/extrlib/pnglibconf.h | 189 + include/nana/extrlib/zlib.h | 1732 ++++++++ include/nana/filesystem/file_iterator.hpp | 255 ++ include/nana/filesystem/fs_utility.hpp | 65 + include/nana/fwd.hpp | 22 + include/nana/gui.hpp | 1 + include/nana/gui/animation.hpp | 82 + include/nana/gui/basis.hpp | 241 ++ include/nana/gui/detail/basic_window.hpp | 241 ++ include/nana/gui/detail/bedrock.hpp | 102 + include/nana/gui/detail/drawer.hpp | 165 + .../gui/detail/dynamic_drawing_object.hpp | 69 + include/nana/gui/detail/effects_renderer.hpp | 152 + include/nana/gui/detail/element_store.hpp | 52 + include/nana/gui/detail/event_code.hpp | 48 + include/nana/gui/detail/events_holder.hpp | 20 + include/nana/gui/detail/events_operation.hpp | 35 + include/nana/gui/detail/general_events.hpp | 497 +++ include/nana/gui/detail/handle_manager.hpp | 287 ++ include/nana/gui/detail/inner_fwd.hpp | 55 + .../nana/gui/detail/inner_fwd_implement.hpp | 201 + .../nana/gui/detail/internal_scope_guard.hpp | 31 + .../gui/detail/native_window_interface.hpp | 89 + include/nana/gui/detail/runtime_manager.hpp | 100 + include/nana/gui/detail/window_layout.hpp | 88 + include/nana/gui/detail/window_manager.hpp | 225 + include/nana/gui/dragger.hpp | 29 + include/nana/gui/drawing.hpp | 49 + include/nana/gui/effects.hpp | 67 + include/nana/gui/element.hpp | 194 + include/nana/gui/filebox.hpp | 60 + include/nana/gui/layout_utility.hpp | 43 + include/nana/gui/msgbox.hpp | 96 + include/nana/gui/notifier.hpp | 67 + include/nana/gui/place.hpp | 130 + include/nana/gui/programming_interface.hpp | 260 ++ include/nana/gui/state_cursor.hpp | 28 + include/nana/gui/timer.hpp | 60 + include/nana/gui/tooltip.hpp | 76 + include/nana/gui/widgets/button.hpp | 113 + include/nana/gui/widgets/categorize.hpp | 247 ++ include/nana/gui/widgets/checkbox.hpp | 100 + include/nana/gui/widgets/combox.hpp | 233 + include/nana/gui/widgets/date_chooser.hpp | 123 + include/nana/gui/widgets/detail/compset.hpp | 84 + include/nana/gui/widgets/detail/tree_cont.hpp | 518 +++ include/nana/gui/widgets/float_listbox.hpp | 107 + include/nana/gui/widgets/form.hpp | 64 + include/nana/gui/widgets/frame.hpp | 53 + include/nana/gui/widgets/label.hpp | 78 + include/nana/gui/widgets/listbox.hpp | 550 +++ include/nana/gui/widgets/menu.hpp | 200 + include/nana/gui/widgets/menubar.hpp | 113 + include/nana/gui/widgets/panel.hpp | 71 + include/nana/gui/widgets/picture.hpp | 81 + include/nana/gui/widgets/progress.hpp | 73 + include/nana/gui/widgets/scroll.hpp | 444 ++ .../gui/widgets/skeletons/text_editor.hpp | 335 ++ .../widgets/skeletons/text_token_stream.hpp | 952 +++++ .../nana/gui/widgets/skeletons/textbase.hpp | 539 +++ .../skeletons/textbase_export_interface.hpp | 32 + include/nana/gui/widgets/slider.hpp | 142 + include/nana/gui/widgets/tabbar.hpp | 332 ++ include/nana/gui/widgets/textbox.hpp | 189 + include/nana/gui/widgets/toolbar.hpp | 102 + include/nana/gui/widgets/treebox.hpp | 440 ++ include/nana/gui/widgets/widget.hpp | 499 +++ include/nana/gui/wvl.hpp | 45 + include/nana/internationalization.hpp | 211 + include/nana/key_type.hpp | 123 + include/nana/paint/detail/image_bmp.hpp | 359 ++ include/nana/paint/detail/image_ico.hpp | 43 + .../paint/detail/image_impl_interface.hpp | 29 + include/nana/paint/detail/image_png.hpp | 188 + .../paint/detail/image_process_provider.hpp | 127 + include/nana/paint/detail/image_processor.hpp | 676 +++ .../paint/detail/native_paint_interface.hpp | 42 + include/nana/paint/gadget.hpp | 38 + include/nana/paint/graphics.hpp | 166 + include/nana/paint/image.hpp | 54 + .../nana/paint/image_process_interface.hpp | 85 + include/nana/paint/image_process_selector.hpp | 71 + include/nana/paint/pixel_buffer.hpp | 93 + include/nana/paint/text_renderer.hpp | 28 + include/nana/pat/cloneable.hpp | 216 + include/nana/std_condition_variable.hpp | 12 + include/nana/std_mutex.hpp | 22 + include/nana/std_thread.hpp | 13 + include/nana/system/dataexch.hpp | 38 + include/nana/system/platform.hpp | 46 + include/nana/system/shared_wrapper.hpp | 100 + include/nana/system/timepiece.hpp | 38 + include/nana/threads/pool.hpp | 123 + include/nana/traits.hpp | 539 +++ include/nana/unicode_bidi.hpp | 75 + source/any.cpp | 70 + source/audio/detail/audio_device.cpp | 237 ++ source/audio/detail/audio_stream.cpp | 91 + source/audio/detail/buffer_preparation.cpp | 161 + source/audio/player.cpp | 65 + source/basic_types.cpp | 313 ++ source/charset.cpp | 1071 +++++ source/datetime.cpp | 274 ++ source/deploy.cpp | 73 + source/detail/linux_X11/platform_spec.cpp | 1330 ++++++ source/detail/platform_spec_selector.cpp | 22 + source/detail/win32/platform_spec.cpp | 246 ++ source/exceptions.cpp | 71 + source/filesystem/file_iterator.cpp | 41 + source/filesystem/fs_utility.cpp | 443 ++ source/gui/animation.cpp | 642 +++ source/gui/basis.cpp | 33 + source/gui/detail/basic_window.cpp | 385 ++ source/gui/detail/bedrock_pi.cpp | 331 ++ source/gui/detail/bedrock_selector.cpp | 23 + source/gui/detail/drawer.cpp | 388 ++ source/gui/detail/element_store.cpp | 45 + source/gui/detail/events_operation.cpp | 52 + source/gui/detail/linux_X11/bedrock.cpp | 1295 ++++++ source/gui/detail/native_window_interface.cpp | 1369 ++++++ source/gui/detail/win32/bedrock.cpp | 1801 ++++++++ source/gui/detail/window_layout.cpp | 391 ++ source/gui/detail/window_manager.cpp | 1415 +++++++ source/gui/dragger.cpp | 219 + source/gui/drawing.cpp | 86 + source/gui/effects.cpp | 78 + source/gui/element.cpp | 820 ++++ source/gui/filebox.cpp | 1011 +++++ source/gui/layout_utility.cpp | 264 ++ source/gui/msgbox.cpp | 464 ++ source/gui/notifier.cpp | 360 ++ source/gui/place.cpp | 2219 ++++++++++ source/gui/programming_interface.cpp | 1197 ++++++ source/gui/state_cursor.cpp | 62 + source/gui/timer.cpp | 238 ++ source/gui/tooltip.cpp | 355 ++ source/gui/widgets/button.cpp | 492 +++ source/gui/widgets/categorize.cpp | 942 +++++ source/gui/widgets/checkbox.cpp | 243 ++ source/gui/widgets/combox.cpp | 1037 +++++ source/gui/widgets/date_chooser.cpp | 675 +++ source/gui/widgets/float_listbox.cpp | 520 +++ source/gui/widgets/form.cpp | 81 + source/gui/widgets/frame.cpp | 47 + source/gui/widgets/label.cpp | 872 ++++ source/gui/widgets/listbox.cpp | 3761 +++++++++++++++++ source/gui/widgets/menu.cpp | 1389 ++++++ source/gui/widgets/menubar.cpp | 608 +++ source/gui/widgets/panel.cpp | 42 + source/gui/widgets/picture.cpp | 299 ++ source/gui/widgets/progress.cpp | 205 + source/gui/widgets/scroll.cpp | 341 ++ source/gui/widgets/skeletons/text_editor.cpp | 2845 +++++++++++++ source/gui/widgets/slider.cpp | 788 ++++ source/gui/widgets/tabbar.cpp | 1293 ++++++ source/gui/widgets/textbox.cpp | 515 +++ source/gui/widgets/toolbar.cpp | 514 +++ source/gui/widgets/treebox.cpp | 2248 ++++++++++ source/gui/widgets/widget.cpp | 286 ++ source/gui/wvl.cpp | 22 + source/internationalization.cpp | 500 +++ .../paint/detail/image_process_provider.cpp | 119 + .../paint/detail/native_paint_interface.cpp | 230 + source/paint/gadget.cpp | 316 ++ source/paint/graphics.cpp | 1189 ++++++ source/paint/image.cpp | 276 ++ source/paint/image_process_selector.cpp | 42 + source/paint/pixel_buffer.cpp | 1130 +++++ source/paint/text_renderer.cpp | 590 +++ source/system/dataexch.cpp | 173 + source/system/platform.cpp | 116 + source/system/shared_wrapper.cpp | 125 + source/system/timepiece.cpp | 76 + source/threads/pool.cpp | 399 ++ source/traits.cpp | 20 + source/unicode_bidi.cpp | 1098 +++++ 206 files changed, 69773 insertions(+) create mode 100644 LICENSE_1_0.txt create mode 100644 build/codeblocks/nana.cbp create mode 100644 build/codeblocks/nana.depend create mode 100644 build/codeblocks/nana.layout create mode 100644 build/makefile/makefile create mode 100644 build/makefile/readme.txt create mode 100644 build/vc2013/nana.sln create mode 100644 build/vc2013/nana.v12.suo create mode 100644 build/vc2013/nana.vcxproj create mode 100644 build/vc2013/nana.vcxproj.filters create mode 100644 extrlib/readme.txt create mode 100644 how-to-install.txt create mode 100644 include/nana/any.hpp create mode 100644 include/nana/audio/detail/audio_device.hpp create mode 100644 include/nana/audio/detail/audio_stream.hpp create mode 100644 include/nana/audio/detail/buffer_preparation.hpp create mode 100644 include/nana/audio/player.hpp create mode 100644 include/nana/basic_types.hpp create mode 100644 include/nana/charset.hpp create mode 100644 include/nana/concepts.hpp create mode 100644 include/nana/config.hpp create mode 100644 include/nana/datetime.hpp create mode 100644 include/nana/deploy.hpp create mode 100644 include/nana/detail/linux_X11/msg_dispatcher.hpp create mode 100644 include/nana/detail/linux_X11/msg_packet.hpp create mode 100644 include/nana/detail/linux_X11/platform_spec.hpp create mode 100644 include/nana/detail/win32/platform_spec.hpp create mode 100644 include/nana/exceptions.hpp create mode 100644 include/nana/extrlib/png.h create mode 100644 include/nana/extrlib/pngconf.h create mode 100644 include/nana/extrlib/pnglibconf.h create mode 100644 include/nana/extrlib/zlib.h create mode 100644 include/nana/filesystem/file_iterator.hpp create mode 100644 include/nana/filesystem/fs_utility.hpp create mode 100644 include/nana/fwd.hpp create mode 100644 include/nana/gui.hpp create mode 100644 include/nana/gui/animation.hpp create mode 100644 include/nana/gui/basis.hpp create mode 100644 include/nana/gui/detail/basic_window.hpp create mode 100644 include/nana/gui/detail/bedrock.hpp create mode 100644 include/nana/gui/detail/drawer.hpp create mode 100644 include/nana/gui/detail/dynamic_drawing_object.hpp create mode 100644 include/nana/gui/detail/effects_renderer.hpp create mode 100644 include/nana/gui/detail/element_store.hpp create mode 100644 include/nana/gui/detail/event_code.hpp create mode 100644 include/nana/gui/detail/events_holder.hpp create mode 100644 include/nana/gui/detail/events_operation.hpp create mode 100644 include/nana/gui/detail/general_events.hpp create mode 100644 include/nana/gui/detail/handle_manager.hpp create mode 100644 include/nana/gui/detail/inner_fwd.hpp create mode 100644 include/nana/gui/detail/inner_fwd_implement.hpp create mode 100644 include/nana/gui/detail/internal_scope_guard.hpp create mode 100644 include/nana/gui/detail/native_window_interface.hpp create mode 100644 include/nana/gui/detail/runtime_manager.hpp create mode 100644 include/nana/gui/detail/window_layout.hpp create mode 100644 include/nana/gui/detail/window_manager.hpp create mode 100644 include/nana/gui/dragger.hpp create mode 100644 include/nana/gui/drawing.hpp create mode 100644 include/nana/gui/effects.hpp create mode 100644 include/nana/gui/element.hpp create mode 100644 include/nana/gui/filebox.hpp create mode 100644 include/nana/gui/layout_utility.hpp create mode 100644 include/nana/gui/msgbox.hpp create mode 100644 include/nana/gui/notifier.hpp create mode 100644 include/nana/gui/place.hpp create mode 100644 include/nana/gui/programming_interface.hpp create mode 100644 include/nana/gui/state_cursor.hpp create mode 100644 include/nana/gui/timer.hpp create mode 100644 include/nana/gui/tooltip.hpp create mode 100644 include/nana/gui/widgets/button.hpp create mode 100644 include/nana/gui/widgets/categorize.hpp create mode 100644 include/nana/gui/widgets/checkbox.hpp create mode 100644 include/nana/gui/widgets/combox.hpp create mode 100644 include/nana/gui/widgets/date_chooser.hpp create mode 100644 include/nana/gui/widgets/detail/compset.hpp create mode 100644 include/nana/gui/widgets/detail/tree_cont.hpp create mode 100644 include/nana/gui/widgets/float_listbox.hpp create mode 100644 include/nana/gui/widgets/form.hpp create mode 100644 include/nana/gui/widgets/frame.hpp create mode 100644 include/nana/gui/widgets/label.hpp create mode 100644 include/nana/gui/widgets/listbox.hpp create mode 100644 include/nana/gui/widgets/menu.hpp create mode 100644 include/nana/gui/widgets/menubar.hpp create mode 100644 include/nana/gui/widgets/panel.hpp create mode 100644 include/nana/gui/widgets/picture.hpp create mode 100644 include/nana/gui/widgets/progress.hpp create mode 100644 include/nana/gui/widgets/scroll.hpp create mode 100644 include/nana/gui/widgets/skeletons/text_editor.hpp create mode 100644 include/nana/gui/widgets/skeletons/text_token_stream.hpp create mode 100644 include/nana/gui/widgets/skeletons/textbase.hpp create mode 100644 include/nana/gui/widgets/skeletons/textbase_export_interface.hpp create mode 100644 include/nana/gui/widgets/slider.hpp create mode 100644 include/nana/gui/widgets/tabbar.hpp create mode 100644 include/nana/gui/widgets/textbox.hpp create mode 100644 include/nana/gui/widgets/toolbar.hpp create mode 100644 include/nana/gui/widgets/treebox.hpp create mode 100644 include/nana/gui/widgets/widget.hpp create mode 100644 include/nana/gui/wvl.hpp create mode 100644 include/nana/internationalization.hpp create mode 100644 include/nana/key_type.hpp create mode 100644 include/nana/paint/detail/image_bmp.hpp create mode 100644 include/nana/paint/detail/image_ico.hpp create mode 100644 include/nana/paint/detail/image_impl_interface.hpp create mode 100644 include/nana/paint/detail/image_png.hpp create mode 100644 include/nana/paint/detail/image_process_provider.hpp create mode 100644 include/nana/paint/detail/image_processor.hpp create mode 100644 include/nana/paint/detail/native_paint_interface.hpp create mode 100644 include/nana/paint/gadget.hpp create mode 100644 include/nana/paint/graphics.hpp create mode 100644 include/nana/paint/image.hpp create mode 100644 include/nana/paint/image_process_interface.hpp create mode 100644 include/nana/paint/image_process_selector.hpp create mode 100644 include/nana/paint/pixel_buffer.hpp create mode 100644 include/nana/paint/text_renderer.hpp create mode 100644 include/nana/pat/cloneable.hpp create mode 100644 include/nana/std_condition_variable.hpp create mode 100644 include/nana/std_mutex.hpp create mode 100644 include/nana/std_thread.hpp create mode 100644 include/nana/system/dataexch.hpp create mode 100644 include/nana/system/platform.hpp create mode 100644 include/nana/system/shared_wrapper.hpp create mode 100644 include/nana/system/timepiece.hpp create mode 100644 include/nana/threads/pool.hpp create mode 100644 include/nana/traits.hpp create mode 100644 include/nana/unicode_bidi.hpp create mode 100644 source/any.cpp create mode 100644 source/audio/detail/audio_device.cpp create mode 100644 source/audio/detail/audio_stream.cpp create mode 100644 source/audio/detail/buffer_preparation.cpp create mode 100644 source/audio/player.cpp create mode 100644 source/basic_types.cpp create mode 100644 source/charset.cpp create mode 100644 source/datetime.cpp create mode 100644 source/deploy.cpp create mode 100644 source/detail/linux_X11/platform_spec.cpp create mode 100644 source/detail/platform_spec_selector.cpp create mode 100644 source/detail/win32/platform_spec.cpp create mode 100644 source/exceptions.cpp create mode 100644 source/filesystem/file_iterator.cpp create mode 100644 source/filesystem/fs_utility.cpp create mode 100644 source/gui/animation.cpp create mode 100644 source/gui/basis.cpp create mode 100644 source/gui/detail/basic_window.cpp create mode 100644 source/gui/detail/bedrock_pi.cpp create mode 100644 source/gui/detail/bedrock_selector.cpp create mode 100644 source/gui/detail/drawer.cpp create mode 100644 source/gui/detail/element_store.cpp create mode 100644 source/gui/detail/events_operation.cpp create mode 100644 source/gui/detail/linux_X11/bedrock.cpp create mode 100644 source/gui/detail/native_window_interface.cpp create mode 100644 source/gui/detail/win32/bedrock.cpp create mode 100644 source/gui/detail/window_layout.cpp create mode 100644 source/gui/detail/window_manager.cpp create mode 100644 source/gui/dragger.cpp create mode 100644 source/gui/drawing.cpp create mode 100644 source/gui/effects.cpp create mode 100644 source/gui/element.cpp create mode 100644 source/gui/filebox.cpp create mode 100644 source/gui/layout_utility.cpp create mode 100644 source/gui/msgbox.cpp create mode 100644 source/gui/notifier.cpp create mode 100644 source/gui/place.cpp create mode 100644 source/gui/programming_interface.cpp create mode 100644 source/gui/state_cursor.cpp create mode 100644 source/gui/timer.cpp create mode 100644 source/gui/tooltip.cpp create mode 100644 source/gui/widgets/button.cpp create mode 100644 source/gui/widgets/categorize.cpp create mode 100644 source/gui/widgets/checkbox.cpp create mode 100644 source/gui/widgets/combox.cpp create mode 100644 source/gui/widgets/date_chooser.cpp create mode 100644 source/gui/widgets/float_listbox.cpp create mode 100644 source/gui/widgets/form.cpp create mode 100644 source/gui/widgets/frame.cpp create mode 100644 source/gui/widgets/label.cpp create mode 100644 source/gui/widgets/listbox.cpp create mode 100644 source/gui/widgets/menu.cpp create mode 100644 source/gui/widgets/menubar.cpp create mode 100644 source/gui/widgets/panel.cpp create mode 100644 source/gui/widgets/picture.cpp create mode 100644 source/gui/widgets/progress.cpp create mode 100644 source/gui/widgets/scroll.cpp create mode 100644 source/gui/widgets/skeletons/text_editor.cpp create mode 100644 source/gui/widgets/slider.cpp create mode 100644 source/gui/widgets/tabbar.cpp create mode 100644 source/gui/widgets/textbox.cpp create mode 100644 source/gui/widgets/toolbar.cpp create mode 100644 source/gui/widgets/treebox.cpp create mode 100644 source/gui/widgets/widget.cpp create mode 100644 source/gui/wvl.cpp create mode 100644 source/internationalization.cpp create mode 100644 source/paint/detail/image_process_provider.cpp create mode 100644 source/paint/detail/native_paint_interface.cpp create mode 100644 source/paint/gadget.cpp create mode 100644 source/paint/graphics.cpp create mode 100644 source/paint/image.cpp create mode 100644 source/paint/image_process_selector.cpp create mode 100644 source/paint/pixel_buffer.cpp create mode 100644 source/paint/text_renderer.cpp create mode 100644 source/system/dataexch.cpp create mode 100644 source/system/platform.cpp create mode 100644 source/system/shared_wrapper.cpp create mode 100644 source/system/timepiece.cpp create mode 100644 source/threads/pool.cpp create mode 100644 source/traits.cpp create mode 100644 source/unicode_bidi.cpp diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/build/codeblocks/nana.cbp b/build/codeblocks/nana.cbp new file mode 100644 index 00000000..b2021965 --- /dev/null +++ b/build/codeblocks/nana.cbp @@ -0,0 +1,121 @@ + + + + + + diff --git a/build/codeblocks/nana.depend b/build/codeblocks/nana.depend new file mode 100644 index 00000000..a2318fdf --- /dev/null +++ b/build/codeblocks/nana.depend @@ -0,0 +1,539 @@ +# depslib dependency file v1.0 +1363362719 source:d:\privates\nana\release\nana.cpp11\source\any.cpp + + +1362509572 source:d:\privates\nana\release\nana.cpp11\source\audio\detail\audio_device.cpp + + + + + + + +1353115288 source:d:\privates\nana\release\nana.cpp11\source\audio\detail\audio_stream.cpp + + + +1362509721 source:d:\privates\nana\release\nana.cpp11\source\audio\detail\buffer_preparation.cpp + + + +1353253406 source:d:\privates\nana\release\nana.cpp11\source\audio\player.cpp + + + + + + +1380829816 source:d:\privates\nana\release\nana.cpp11\source\basic_types.cpp + + +1376407818 source:d:\privates\nana\release\nana.cpp11\source\charset.cpp + + + + + + + + +1365203880 source:d:\privates\nana\release\nana.cpp11\source\datetime.cpp + + + + +1368515624 source:d:\privates\nana\release\nana.cpp11\source\deploy.cpp + + + + +1356273963 source:d:\privates\nana\release\nana.cpp11\source\detail\win32\platform_spec.cpp + + + + + +1365203880 source:d:\privates\nana\release\nana.cpp11\source\exceptions.cpp + + +1365203878 source:d:\privates\nana\release\nana.cpp11\source\filesystem\file_iterator.cpp + + +1365203878 source:d:\privates\nana\release\nana.cpp11\source\filesystem\fs_utility.cpp + + + + + + + + + + + + + + + + +1365203879 source:d:\privates\nana\release\nana.cpp11\source\gui\basis.cpp + + +1394945360 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\basic_window.cpp + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\drawer.cpp + + + + + + + + +1395848366 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\event_manager.cpp + + + + + +1390762141 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\native_window_interface.cpp + + + + + + + + +1390850442 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\timer_trigger.cpp + + + + + + +1356028060 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\win32\bedrock.cpp + + + + + + +1394946162 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\window_manager.cpp + + + + + + + + +1391060709 source:d:\privates\nana\release\nana.cpp11\source\gui\dragger.cpp + + +1391341193 source:d:\privates\nana\release\nana.cpp11\source\gui\drawing.cpp + + + + +1396881268 source:d:\privates\nana\release\nana.cpp11\source\gui\filebox.cpp + + + + + + + + + + + + + + + + +1342280997 source:d:\privates\nana\release\nana.cpp11\source\gui\functional.cpp + + + +1365203879 source:d:\privates\nana\release\nana.cpp11\source\gui\layout.cpp + + + +1397227563 source:d:\privates\nana\release\nana.cpp11\source\gui\layout_utility.cpp + + +1389116447 source:d:\privates\nana\release\nana.cpp11\source\gui\msgbox.cpp + + + + + + + + + + +1394981871 source:d:\privates\nana\release\nana.cpp11\source\gui\programming_interface.cpp + + + + + + + +1398012918 source:d:\privates\nana\release\nana.cpp11\source\gui\timer.cpp + + +1398101619 source:d:\privates\nana\release\nana.cpp11\source\gui\tooltip.cpp + + + + + +1399003520 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\button.cpp + + + +1397406400 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\categorize.cpp + + + + + + + +1395850855 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\checkbox.cpp + + + + + + +1398356540 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\combox.cpp + + + + + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\date_chooser.cpp + + + + + +1397406413 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\float_listbox.cpp + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\form.cpp + + +1365203878 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\frame.cpp + + +1398365621 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\label.cpp + + + + + + + +1399000256 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\listbox.cpp + + + + + + + + + +1398016208 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\login.cpp + + + + + + + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\menu.cpp + + + + + + + +1394948882 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\menubar.cpp + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\panel.cpp + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\picture.cpp + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\progress.cpp + + +1382857419 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\scroll.cpp + + +1397670961 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\skeletons\text_editor.cpp + + + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\slider.cpp + + +1394949372 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\tabbar.cpp + + + + + + +1398365225 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\textbox.cpp + + + + + +1397936811 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\toolbar.cpp + + + + + +1390938560 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\tray.cpp + + +1398364760 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\treebox.cpp + + + + + + + +1398365335 source:d:\privates\nana\release\nana.cpp11\source\gui\widgets\widget.cpp + + + +1365203879 source:d:\privates\nana\release\nana.cpp11\source\gui\wvl.cpp + + +1382451741 source:d:\privates\nana\release\nana.cpp11\source\paint\detail\image_process_provider.cpp + + + +1383444362 source:d:\privates\nana\release\nana.cpp11\source\paint\detail\native_paint_interface.cpp + + + + + + + +1379767040 source:d:\privates\nana\release\nana.cpp11\source\paint\gadget.cpp + + + +1390741327 source:d:\privates\nana\release\nana.cpp11\source\paint\graphics.cpp + + + + + + + + + + +1383145765 source:d:\privates\nana\release\nana.cpp11\source\paint\image.cpp + + + + + + + + + + + +1376313789 source:d:\privates\nana\release\nana.cpp11\source\paint\image_process_selector.cpp + + +1398195475 source:d:\privates\nana\release\nana.cpp11\source\paint\pixel_buffer.cpp + + + + + + + +1362504379 source:d:\privates\nana\release\nana.cpp11\source\paint\text_renderer.cpp + + + + + +1391437647 source:d:\privates\nana\release\nana.cpp11\source\system\dataexch.cpp + + + + + +1387007333 source:d:\privates\nana\release\nana.cpp11\source\system\platform.cpp + + + + + + + + +1365203879 source:d:\privates\nana\release\nana.cpp11\source\system\shared_wrapper.cpp + + + + + + +1342280997 source:d:\privates\nana\release\nana.cpp11\source\system\timepiece.cpp + + + + + +1386165989 source:d:\privates\nana\release\nana.cpp11\source\threads\pool.cpp + + + + + + + + + + + + + +1365203748 source:d:\privates\nana\release\nana.cpp11\source\traits.cpp + + +1385897272 source:d:\privates\nana\release\nana.cpp11\source\unicode_bidi.cpp + + +1358528462 source:d:\privates\nana\release\nana.cpp11\source\detail\platform_spec_selector.cpp + + "win32/platform_spec.cpp" + "linux_X11/platform_spec.cpp" + +1391342312 d:\privates\nana\release\nana.cpp11\source\detail\win32\platform_spec.cpp + + + + + +1391435023 d:\privates\nana\release\nana.cpp11\source\detail\linux_x11\platform_spec.cpp + + + + + + + + + + + + + +1358528584 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\bedrock_selector.cpp + + "win32/bedrock.cpp" + "linux_X11/bedrock.cpp" + +1399001800 d:\privates\nana\release\nana.cpp11\source\gui\detail\win32\bedrock.cpp + + + + + + + + + + + +1399001985 d:\privates\nana\release\nana.cpp11\source\gui\detail\linux_x11\bedrock.cpp + + + + + + + + + +1398365709 source:d:\privates\nana\release\nana.cpp11\source\gui\place.cpp + + + + + + + + +1391435611 source:d:\privates\nana\release\nana.cpp11\source\gui\animation.cpp + + + + + + + + + + + + + + +1373211308 source:d:\privates\nana\release\nana.cpp11\source\gui\effects.cpp + + + +1386164590 source:d:\privates\nana\release\nana.cpp11\source\gui\element.cpp + + + + + + + +1391342458 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\window_layout.cpp + + + + + + +1399002439 source:d:\privates\nana\release\nana.cpp11\source\gui\detail\element_store.cpp + + diff --git a/build/codeblocks/nana.layout b/build/codeblocks/nana.layout new file mode 100644 index 00000000..469d6a54 --- /dev/null +++ b/build/codeblocks/nana.layout @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/makefile/makefile b/build/makefile/makefile new file mode 100644 index 00000000..2a473da7 --- /dev/null +++ b/build/makefile/makefile @@ -0,0 +1,42 @@ +#Nana C++ Library +# +#Makefile created by Jinhao(cnjinhao@hotmail.com) + +GCC = g++ +INCROOT = ../../include +SRCROOT = ../../source +NANA_INC= $(INCROOT)/nana + +INCS = -I$(INCROOT) -I/usr/include/freetype2 + +BIN = libnana.a + +SRC_NANA = $(wildcard $(SRCROOT)/*.cpp) +SRC_DETAIL = $(wildcard $(SRCROOT)/detail/*.cpp) +SRC_FILESYSTEM = $(wildcard $(SRCROOT)/filesystem/*.cpp) +SRC_AUDIO = $(wildcard $(SRCROOT)/audio/*.cpp) +SRC_AUDIO_DETAIL = $(wildcard $(SRCROOT)/audio/detail/*.cpp) +SRC_GUI = $(wildcard $(SRCROOT)/gui/*.cpp) +SRC_GUI_DETAIL = $(wildcard $(SRCROOT)/gui/detail/*.cpp) +SRC_GUI_WIDGETS = $(wildcard $(SRCROOT)/gui/widgets/*.cpp) +SRC_GUI_WIDGETS_SKELETONS = $(wildcard $(SRCROOT)/gui/widgets/skeletons/*.cpp) +SRC_PAINT = $(wildcard $(SRCROOT)/paint/*.cpp) +SRC_PAINT_DETAIL = $(wildcard $(SRCROOT)/paint/detail/*.cpp) +SRC_SYSTEM = $(wildcard $(SRCROOT)/system/*.cpp) +SRC_THREADS= $(wildcard $(SRCROOT)/threads/*.cpp) + +SOURCES = $(SRC_NANA) $(SRC_DETAIL) $(SRC_FILESYSTEM) $(SRC_AUDIO) $(SRC_AUDIO_DETAIL) $(SRC_GUI) $(SRC_GUI_DETAIL) $(SRC_GUI_WIDGETS) $(SRC_GUI_WIDGETS_SKELETONS) $(SRC_PAINT) $(SRC_PAINT_DETAIL) $(SRC_SYSTEM) $(SRC_THREADS) + +LINKOBJ = $(SOURCES:.cpp=.o) + +$(BIN): $(LINKOBJ) + ar r ../bin/$(BIN) $(LINKOBJ) + ranlib ../bin/$(BIN) + +.cpp.o: + $(GCC) -g -c $< -o $@ $(INCS) -std=c++0x -Wall + +clean: + rm -f $(LINKOBJ) + rm -f ../bin/$(BIN) + diff --git a/build/makefile/readme.txt b/build/makefile/readme.txt new file mode 100644 index 00000000..fc8df43f --- /dev/null +++ b/build/makefile/readme.txt @@ -0,0 +1,31 @@ +Building Nana C++ Library +requires: +X11, pthread, Xpm, rt, dl, freetype2, Xft, fontconfig, ALSA + +Writing a makefile for creating applications with Nana C++ Library +------------------- +GCC = g++ +NANAPATH = [The folder of Nana C++ Library] +BIN = [The bin file what you want to create.] +SOURCES = [The source file of your application.] + +NANAINC = $(NANAPATH)/include +NANALIB = $(NANAPATH)/build/bin + +INCS = -I$(NANAINC) +LIBS = -L$(NANALIB) -lnana -lX11 -lpthread -lrt -lXft -lpng -lasound + +LINKOBJ = $(SOURCES:.cpp=.o) + +$(BIN): $(LINKOBJ) $(NANALIB)/libnana.a + $(GCC) $(LINKOBJ) $(INCS) $(LIBS) -o $(BIN) -std=c++0x + +.cpp.o: + $(GCC) -g -c $< -o $@ $(INCS) -std=c++0x + +$(NANALIB): + make -f $(NANAPATH)/build/makefile/makefile + +clean: + rm -f $(LINKOBJ) +------------------- diff --git a/build/vc2013/nana.sln b/build/vc2013/nana.sln new file mode 100644 index 00000000..6baefd4a --- /dev/null +++ b/build/vc2013/nana.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.Build.0 = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.ActiveCfg = Release|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vc2013/nana.v12.suo b/build/vc2013/nana.v12.suo new file mode 100644 index 0000000000000000000000000000000000000000..d9bff60ccf7241d203d7257050dec8deaab4cf16 GIT binary patch literal 23552 zcmeHPYm8LY9Y3>_7K#Y+(xTGEU0&j>v$M-QKm_(B(8Z-J53Q4s*?BC3%j{+!JgTeJ z5JjW}`=ON&EgCdw4ccmy&{qn4G14>;6WfN;Sksy|scnrW)en{J?|1G!J9qBPea!5z z%fg(=nRD(rXU_kBUjNtqpSf`UroX)S`rHqMDcmb2h|5Eh#g`4`9z$MC7vd{;X4&PT zp&?c=k8C-NqZ!yFy7B23m7-ask@kvxTuRqrj+i*S=C?ci>d0FkEtov{g6C^&ceB=b zBOrE*onjrJCy{FwdmVbouAU<*hT(JCvupD|J%nOxUl}%wsOS?9i&l|B+Ap@?I{}ie1QO zV-ye-o`vY^h63O}sJABya}d9<*sna-40F+j=`5tGYzp$T^>Ws!a0|+~w9^o8L?m9f zA}&GX{$M-etJ+(oi_m5<;$*}-5tky~g{a_L{jOYI*bI#3`4?|bna}fo8`kj}I{zNy zS>Vu|LaERHd;l!={HxtE1AUMV@O+UrPDNzhM5H|bH|ftTGoC@xy_tw#MI=pQeZEko z*Ui(@uOqEQB<^=0@|;&Al9tvW=Ig^)X2ii*Ud|Ub1Dr?337GRQA#%OBrj+fto?I8M zE%!M0821I~I_W$23HJr}4)*~019<{@3i~84Q2jIIxhD@`Uadd#Tz~Elwf?02EGPXZ z-yr>8gGl=CMdbcqy$@+Uq93tNFJpNC`JnzBM!HW5gA;tx5xYS6q+R4& zTnD?hs%`}`$Mpv%_@rfaf$$4m|9jEl8+xaTHci0uXwiSl09-S|o{yCDpZPNVH?HL9 zsj_O^o#r=e+fBV|diN!P?O<%Bzmpg&w|)lmcJZVYs{6VSRr@u&;8A{Ry4 zB>6y8HO-qYECN1xRjuAzyBsZfPzt#;xFNr32jMKViJsw_{FJz+2>7&rDEgbtc{c;@ zfV4v>dq}V3ObWZ)Dex5m-#GuYH`HL%J^0k(69IItLoZe(fu~O7Q%JcV$d^-?l?ZGV z%4+eXrwQ^^L`o1Tv0JVfZ4?pAqGrvApsxgemB2G?D-p;~T8$mt9<(8hezfmFZm;ZP zyXXKuNqo3FYk(v1e(c%z?_dAX;=jH7;(P!8^`*})ahA-dCwJzwl09NOaErp~#ZmWX z`h24QP~zp@Pk(##?gKx0@HI(>^YwYKi1Bw~JRFysc~J9j#BsaClq!;BboBBDbFgKmMXVP??a{e{8QHI!HRO^TnD#usN(;$vAG>T+aA*qEX)68`QJ+a;+~|e zY!}r22~jw3E0-a+nQx zN=s_XQe%MqUBZ=vcRBtRbU<0VR6)UZJANZvr}-Z*>rb8D?fA>0dGOA8o~BE&tIT?e_eaTK=Q#N&AUg_*aAccRP)c2wS0(Z3cJaDWJ5!7m_FC&)wj5 z)Bv3V^ncHEG~(D9oZ7RVva;fTPW(sd=~n%c|MMM0A@k2Zf2?=t1mAB3ST8R|{#lCO zUT_J&&INqh(<%|&&i~zL`zu5S%6PQ3_ey=eOX`2r)%#5E1e9HbcA|dNs<6BW`6pZd z>&8ACfX=7&Y}ENSVn6mtsY|oXWS}bOLcspvp(&s5sN9af0d4=PchLkGR`8WCh@Bk@ z_8$*v58rvYg>M{xe*04rqo(FhpAT!>4~GE#clhkNg-@I7P6|v2X8ONPLX6=pgxS+X zYj6Ip#Q6E1Zx*6k_z&pq*_Ro9e*K#*^M}P4Ki^mKJ*8XtThVr}-kljf&jab6lig4M zxwL=KeoY?e7JeJrD*fLKKf`~!<@!6(U}b+{e{SKgN83Af`rihszY}jYX@51J@vV;9 zA8q#)9@6p|1;8i0dJ>VL5qyVs!9H-J6y|+T4i;KFt8dU>!S~9vsk$A%@%(K8J)_ly z_GbE7W!q!(QJic{Mr!|dg3tYE7mBfe8^?dG@PE=Yx9eZ#|JN4(C-0>V*6sS2n*US& zDCGUK@%)Vi|E~hRpXl`8%zwrs|0n+)Oa4!vr$YE|iTS_W_uTsoK*cePHUF;!hGqV* zEz?-@e<%HSy!ihVqW^_3^`-XzsX(7@&)?PL|MS3k&Rp@KI>&>qPgFvd_u*5EH`DyK z3xs|MT413*1Xt=Ex@MXB&M0A&hUP*2p87s*Fv_Dr(LQy%*K z{bT#vKFfzTPCx_vmh0ie9EN?(i>I)j3y4EwH2?H)O5kJX+hgS$qgh)|jKc2B#g1M@ zJTbe0`*wpL5^>eMHF%DaXhq9O<~)%;@4mtq(`rU9VtP4cJc%^faDNf7-S`I;;wPou z&^(fbNtym<`%qnP^xvJwULo8za|+d2rSC)(R<@M*wtjk9k~y2y-418%%F<({{OHVl zNYO#<-B$)D+LRBB5l-5>kPL6sZsm}*Fc^I)AC-5msmdo2AHhwSW#BG;a2%fqz>M38WS^C{GYhSW*q7QFk@sw&g?+eIij>+I#T^IBi}Vf?ip%==Hc zu-~KWY={2>k1u^MHeeuKQYzQHmU(+^0B=y$yENXqq<@AGE98B$V)&HRKCOXPxkvYw zR&cdj8%C&nL!Tcvb>nd*EVv8Ns+72`5UU(}M1v89{92{;Y;7{h58EWS=gF>t48hwt zym`0-Io<&>&LMBkmU4D#EGUc<9<&&(0gjp$_{u2h&wM+ax&K0fQn(iSLhP+i&ph?S z`j*qb|L~r{|DNQ+8_XLr%d$ek_eVJXY`M32$;2Q1^T3kUgO5La{8D0G12M73FoE~= zN!WF`Qzl7DoS$#3u#igWheH~oQE(DwhSX{}h&6cIH!t_$^GG}x3e@^zL2o!5@O$e! zLUrEovUu3*4}^U6fp|3TuZs?5n%C7Qf`LS+)|*JwN4>SRai2Gu@F%=JU(^>1`;y6I ztj^Hfmkfo1VZYBC^LGT;-0uz71(%_D$QKLN2jk(W&(J&&st*N2p^(?_(|WJ-hJuL> zG>`e}lfiJXHo9z(Y>_4h8M4n&_Wor9ck>sKo)Np`?U*!pb_D;K({ru+Gz|$Y z*Bg<(Hw;{_V&<>^%Gyu!t3(&NX74|7^QmVho?7|d>b-BC;Q(^TjJx$eJVN?MN^W-# zu|RQ1%y_n??YXMc(*qN~H~W)!2I-cNGc@CF^q{^AvDC{Tg-gl9wf*hK38=*miVz_L z&Bv2xVtmX0^t;gIe<6N}2TmwsF&9(q&0N+~n$a&vN_dfv zNlHa~7)v_wFDF+-`*5W{jJ5vZ&Q4{uPsfM;VXX&Xr;aGtTlcJHtp@*DlWj*FuX;dP z{vR3V7^(cP^f32&K( + + + + Debug + Win32 + + + Release + Win32 + + + + {25B21068-491B-4A9F-B99F-6C27BF31BAAD} + Win32Proj + nana + + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + ../bin/vc2013/ + + + ../bin/vc2013/ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + + + $(OutDir)\nana_debug.lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + $(OutDir)\nana_release.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters new file mode 100644 index 00000000..3309f037 --- /dev/null +++ b/build/vc2013/nana.vcxproj.filters @@ -0,0 +1,295 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b0bd11b1-bcbb-4e05-885e-44295bc1a7bb} + + + {aab16aa3-c8d4-4495-8606-1b21ae739ee5} + + + {c395f107-7102-415b-a019-54e7cf3575af} + + + {e2569be2-9e68-477d-8b59-e248595de6c7} + + + {52ed7f8e-fa48-495e-af1f-4df013205a35} + + + {87d14798-9015-4162-b9ab-72c741cff063} + + + {4f8e7d23-9fe1-4409-bb03-2bd0809e606b} + + + {85c9c1bb-d87b-4481-bf3c-7425f680a12d} + + + {8058b530-86ec-4d72-890d-345aa30db056} + + + {87b124cb-408d-460b-a81b-8a788bbae0d9} + + + {b10db2f1-0542-421a-9e1d-4357e3be5f68} + + + {59f186c8-f5f8-4499-8e19-f278d4754220} + + + {5acf1733-47b2-4872-a105-66c7ad15cd39} + + + {a81fa10e-1274-44e0-92a0-434fa28f89ae} + + + {e95b4a72-643f-4416-af95-b0bbaf7f0c57} + + + + + Source Files\nana\audio\detail + + + Source Files\nana\audio\detail + + + Source Files\nana\audio\detail + + + Source Files\nana\audio + + + Source Files\nana\detail\win32 + + + Source Files\nana\filesystem + + + Source Files\nana\filesystem + + + Source Files\nana\gui\detail\win32 + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\widgets\skeletons + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\paint\detail + + + Source Files\nana\paint\detail + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\threads + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana + + + \ No newline at end of file diff --git a/extrlib/readme.txt b/extrlib/readme.txt new file mode 100644 index 00000000..e5edb297 --- /dev/null +++ b/extrlib/readme.txt @@ -0,0 +1 @@ +You can download the precompiled external libraries at http://sourceforge.net/projects/nanapro/files/extrlib/ \ No newline at end of file diff --git a/how-to-install.txt b/how-to-install.txt new file mode 100644 index 00000000..5e18a1a2 --- /dev/null +++ b/how-to-install.txt @@ -0,0 +1,7 @@ +Please refer to the Library Installation Documentation for the detailed installation instructions. +http://nanapro.org/en-us/help/instl_lib_doc.htm +NOTE: The method of library installation for VC2003/2005/2008/2010/2012 is only for the version older than 0.8. Since version 0.8, the library only works in VC2013 and later. If you have not VC2013 installed, please choose the latest Codeblocks instead. + +请参考库安装文档获取详细的安装步骤。 +http://nanapro.org/zh-cn/help/instl_lib_doc.htm +注意: 针对VC2003/2005/2008/2010/2012的安装方法只适用于低于0.8的版本。从0.8版起,该库对Visual C++的最低版本要求是2013。如果您没有安装VC2013,可以使用最新版的CodeBlocks代替。 \ No newline at end of file diff --git a/include/nana/any.hpp b/include/nana/any.hpp new file mode 100644 index 00000000..de3e7703 --- /dev/null +++ b/include/nana/any.hpp @@ -0,0 +1,145 @@ +#ifndef NANA_ANY_HPP +#define NANA_ANY_HPP +#include +#include //C++11 for std::move + +namespace nana +{ + + class any + { + struct super_type + { + virtual ~super_type(); + super_type& operator=(const super_type&); + virtual super_type& assign(const super_type&) = 0; + virtual bool same(const super_type&) const = 0; + virtual super_type* clone() const = 0; + }; //end struct super_type + + template + struct object_type + : public super_type + { + object_type(){} + + object_type(T const & obj) + : object(obj) + {} + + object_type(T && obj) + : object(std::move(obj)) + {} + + object_type(const object_type& rhs) + :object(rhs.object) + {} + + virtual super_type& assign(const super_type& rhs) + { + if(this != &rhs) + { + auto other = dynamic_cast(&rhs); + if(other) + object = other->object; + } + return *this; + } + + virtual bool same(const super_type& rhs) const + { + return (dynamic_cast(&rhs) != nullptr); + } + + virtual super_type* clone() const + { + return new object_type(object); + } + + T object; + }; //end struct object_type + public: + template + any(const T & obj) + : super_(new object_type::type>(obj)) + {} + + template + any(T && obj) + : super_(new object_type::type>(std::move(obj))) + {} + + any(); + any(const any&); + any(any&&); + ~any(); + + bool same(const any &) const; + any& operator=(const any&); + any& operator=(any&&); + + template + any& operator=(T const &rhs) + { + T * obj = get(); + if(nullptr == obj) + { + delete super_; + super_ = new object_type(rhs); + } + else + *obj = rhs; + return *this; + } + + template + any & operator=(T && rhs) + { + typedef typename std::remove_cv::type>::type type; + type* obj = get(); + if(nullptr == obj) + { + delete super_; + super_ = new object_type(std::move(rhs)); + } + else + *obj = std::move(rhs); + return *this; + } + + template + T * get() const + { + if(super_) + { + typedef typename std::remove_const::type type; + object_type* obj = dynamic_cast*>(super_); + if(obj) return &(obj->object); + } + return nullptr; + } + + template + operator T&() const + { + typedef typename std::remove_const::type type; + type *obj = get(); + + if(nullptr == obj) + throw std::bad_cast(); + + return *obj; + } + + template + operator T*() const + { + typedef typename std::remove_const::type type; + return get(); + } + private: + super_type * super_; + }; +}//end namespace nana + +#endif diff --git a/include/nana/audio/detail/audio_device.hpp b/include/nana/audio/detail/audio_device.hpp new file mode 100644 index 00000000..375d1595 --- /dev/null +++ b/include/nana/audio/detail/audio_device.hpp @@ -0,0 +1,53 @@ +#ifndef NANA_AUDIO_DETAIL_AUDIO_DEVICE_HPP +#define NANA_AUDIO_DETAIL_AUDIO_DEVICE_HPP + +#include +#include +#include +#if defined(NANA_WINDOWS) + #include +#elif defined(NANA_LINUX) + #include +#endif + +namespace nana{ namespace audio +{ + namespace detail + { + class audio_device + { + public: + audio_device(); + ~audio_device(); + + bool empty() const; + bool open(std::size_t channels, std::size_t rate, std::size_t bits_per_sample); + void close(); + void prepare(buffer_preparation & buf_prep); + void write(buffer_preparation::meta * m); + void wait_for_drain() const; + private: +#if defined(NANA_WINDOWS) + static void __stdcall _m_dev_callback(HWAVEOUT handle, UINT msg, audio_device * self, DWORD_PTR, DWORD_PTR); +#endif + + +#if defined(NANA_WINDOWS) + HWAVEOUT handle_; + std::recursive_mutex queue_lock_; + std::vector done_queue_; +#elif defined(NANA_LINUX) + snd_pcm_t * handle_; + std::size_t rate_; + std::size_t channels_; + std::size_t bytes_per_sample_; + std::size_t bytes_per_frame_; +#endif + buffer_preparation * buf_prep_; + }; + + }//end namespace detail +}//end namespace audio +}//end namespace nana + +#endif diff --git a/include/nana/audio/detail/audio_stream.hpp b/include/nana/audio/detail/audio_stream.hpp new file mode 100644 index 00000000..694089bd --- /dev/null +++ b/include/nana/audio/detail/audio_stream.hpp @@ -0,0 +1,81 @@ +#ifndef NANA_AUDIO_DETAIL_AUDIO_STREAM_HPP +#define NANA_AUDIO_DETAIL_AUDIO_STREAM_HPP +#include +#include + +namespace nana{ namespace audio{ + namespace detail + { + namespace wave_spec + { + #if defined(NANA_WINDOWS) + #pragma pack(1) + struct master_riff_chunk + { + unsigned long ckID; //"RIFF" + unsigned long cksize; + unsigned long waveID; //"WAVE" + }; + + struct format_chunck + { + unsigned long ckID; //"fmt " + unsigned long cksize; + unsigned short wFormatTag; + unsigned short nChannels; + unsigned long nSamplePerSec; + unsigned long nAvgBytesPerSec; + unsigned short nBlockAlign; + unsigned short wBitsPerSample; + }; + #pragma pack() + #elif defined(NANA_LINUX) + struct master_riff_chunk + { + unsigned long ckID; //"RIFF" + unsigned long cksize; + unsigned long waveID; //"WAVE" + }__attribute__((packed)); + + struct format_chunck + { + unsigned long ckID; //"fmt " + unsigned long cksize; + unsigned short wFormatTag; + unsigned short nChannels; + unsigned long nSamplePerSec; + unsigned long nAvgBytesPerSec; + unsigned short nBlockAlign; + unsigned short wBitsPerSample; + }__attribute__((packed)); + #endif + } + + class audio_stream + { + struct chunck + { + unsigned long ckID; + unsigned long cksize; + }; + public: + bool open(const nana::string& file); + void close(); + bool empty() const; + const wave_spec::format_chunck & format() const; + std::size_t data_length() const; + void locate(); + std::size_t read(void * buf, std::size_t len); + private: + std::size_t _m_locate_chunck(unsigned ckID); + private: + std::ifstream fs_; + wave_spec::format_chunck ck_format_; + std::size_t pcm_data_pos_; + std::size_t pcm_data_size_; + std::size_t data_size_; + }; //end class audio_stream + } +}//end namespace audio +}//end namespace nana +#endif diff --git a/include/nana/audio/detail/buffer_preparation.hpp b/include/nana/audio/detail/buffer_preparation.hpp new file mode 100644 index 00000000..fdffc91c --- /dev/null +++ b/include/nana/audio/detail/buffer_preparation.hpp @@ -0,0 +1,65 @@ +#ifndef NANA_AUDIO_DETAIL_BUFFER_PREPARATION_HPP +#define NANA_AUDIO_DETAIL_BUFFER_PREPARATION_HPP +#include +#include + +#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) + #include + #include + #include +#else + #include + #include + #include +#endif + +#include +#include + +#if defined(NANA_WINDOWS) + #include +#endif + +namespace nana{ namespace audio +{ + namespace detail + { + class buffer_preparation + { + public: +#if defined(NANA_WINDOWS) + typedef WAVEHDR meta; +#elif defined(NANA_LINUX) + struct meta + { + char * buf; + std::size_t bufsize; + }; +#endif + + public: + buffer_preparation(audio_stream& as, std::size_t seconds); + + ~buffer_preparation(); + + meta * read(); + //Revert the meta that returned by read() + void revert(meta * m); + bool data_finished() const; + private: + void _m_prepare_routine(); + private: + volatile bool running_; + volatile bool wait_for_buffer_; + std::thread thr_; + mutable std::mutex token_buffer_, token_prepared_; + mutable std::condition_variable cond_buffer_, cond_prepared_; + + std::vector buffer_, prepared_; + std::size_t block_size_; + audio_stream & as_; + }; + }//end namespace detail +}//end namespace audio +}//end namespace nana +#endif diff --git a/include/nana/audio/player.hpp b/include/nana/audio/player.hpp new file mode 100644 index 00000000..278e0ecc --- /dev/null +++ b/include/nana/audio/player.hpp @@ -0,0 +1,25 @@ +#ifndef NANA_AUDIO_PLAYER_HPP +#define NANA_AUDIO_PLAYER_HPP +#include +#include + +namespace nana{ namespace audio +{ /// play an audio file in Windows WAV format + class player + : private nana::noncopyable + { + struct implementation; + public: + player(); + player(const nana::string& file); + ~player(); + + bool open(const nana::string& file); + void play(); + void close(); + private: + implementation* impl_; + }; +}//end namespace audio +}//end namespace nana +#endif \ No newline at end of file diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp new file mode 100644 index 00000000..05088e89 --- /dev/null +++ b/include/nana/basic_types.hpp @@ -0,0 +1,254 @@ +/* + * Basic Types definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/basic_types.hpp + */ + +#ifndef NANA_BASIC_TYPES_HPP +#define NANA_BASIC_TYPES_HPP + +#include + +namespace nana +{ + //A constant value for the invalid position. + const std::size_t npos = static_cast(-1); + + + template + struct casei_char_traits + : public std::char_traits + { + typedef CharT char_type; + + + //static constexpr bool eq(char_type c1, char_type c2) noexcept + //VC2012 does not support constexpr and noexcept keywords + static bool eq(char_type c1, char_type c2) + { + return std::toupper(c1) == std::toupper(c2); + } + + //static constexpr bool lt(char_type c1, char_type c2) noexcept + //VC2012 does not support constexpr and noexcept keywords + static bool lt(char_type c1, char_type c2) + { + return std::toupper(c1) < std::toupper(c2); + } + + static int compare(const char_type* s1, const char_type* s2, std::size_t n) + { + while(n--) + { + char_type c1 = std::toupper(*s1); + char_type c2 = std::toupper(*s2); + if(c1 < c2) return -1; + if(c1 > c2) return 1; + ++s1; + ++s2; + } + return 0; + } + + static const char_type* find(const char_type* s, std::size_t n, const char_type& a) + { + char_type ua = std::toupper(a); + const char_type * end = s + n; + while((s != end) && (std::toupper(*s) != ua)) + ++s; + return (s == end ? nullptr : s); + } + }; + + typedef std::basic_string > cistring; + + + namespace detail + { + struct drawable_impl_type; //declearation, defined in platform_spec.hpp + } + + namespace paint + { + typedef nana::detail::drawable_impl_type* drawable_type; + } + + enum class mouse_action + { + begin, normal = begin, over, pressed, end + }; + + enum class element_state + { + normal, + hovered, + focus_normal, + focus_hovered, + pressed, + disabled + }; + + typedef unsigned scalar_t; + typedef unsigned char uint8_t; + typedef unsigned long uint32_t; + typedef unsigned uint_t; + typedef unsigned color_t; + typedef long long long_long_t; + + const color_t null_color = 0xFFFFFFFF; + + struct pixel_rgb_t + { + union + { + struct element_tag + { + unsigned int blue:8; + unsigned int green:8; + unsigned int red:8; + unsigned int alpha_channel:8; + }element; + + color_t color; + }u; + }; + + struct rectangle; + + struct point + { + point(); + point(int x, int y); + point(const rectangle&); + + point& operator=(const rectangle&); + bool operator==(const point&) const; + bool operator!=(const point&) const; + bool operator<(const point&) const; + bool operator<=(const point&) const; + bool operator>(const point&) const; + bool operator>=(const point&) const; + + point operator-(const point&) const; + point operator+(const point&) const; + point& operator-=(const point&); + point& operator+=(const point&); + + int x; + int y; + }; + + struct upoint + { + typedef unsigned value_type; + + upoint(); + upoint(value_type x, value_type y); + bool operator==(const upoint&) const; + bool operator!=(const upoint&) const; + bool operator<(const upoint&) const; + bool operator<=(const upoint&) const; + bool operator>(const upoint&) const; + bool operator>=(const upoint&) const; + + value_type x; + value_type y; + }; + + struct size + { + size(); + size(unsigned width, unsigned height); + size(const rectangle&); + + size& operator=(const rectangle&); + + bool empty() const; ///< true if width * height == 0 + bool is_hit(const point&) const; ///< Assume it is a rectangle at (0,0), and check whether a specified position is in the rectange. + bool operator==(const size& rhs) const; + bool operator!=(const size& rhs) const; + size operator+(const size&) const; + + unsigned width; + unsigned height; + }; + + struct rectangle + { + rectangle(); ///< a zero-size rectangle at (0, 0). + rectangle(int x, int y, unsigned width, unsigned height); + rectangle(const size &); ///< a rectangle with specified size at coordinate (0, 0). + rectangle(const point&, const size& = size()); + + bool operator==(const rectangle& rhs) const; + bool operator!=(const rectangle& rhs) const; + + rectangle& operator=(const point&); + rectangle& operator=(const size&); + + rectangle& set_pos(const point&); + rectangle& set_size(const size&); + + rectangle& pare_off(int pixels); /// + +namespace nana +{ + enum class unicode + { + utf8, utf16, utf32 + }; + + namespace detail + { + class charset_encoding_interface; + } + /// An intelligent charset class for character code conversion. + class charset + { + public: + charset(const charset&); + charset & operator=(const charset&); + charset(charset&&); + charset & operator=(charset&&); + + charset(const std::string&); /// + +namespace nana +{ + namespace concepts + { + /// The Any Objective is an object that may attach to some other object. + template // no dep. on IndexType ?? + class any_objective + { + public: + virtual ~any_objective(){} + + template + void anyobj(const Target& t) + { + nana::any * p = _m_anyobj(true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + *p = t; + } + + template + void anyobj(Target&& t) + { + nana::any * p = _m_anyobj(true); + if(nullptr == 0) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + + *p = std::move(t); + } + + template + Target * anyobj() const ///< Retrieves the attached object. Returns a nullptr if empty or if the type not match. + { + nana::any * p = _m_anyobj(false); + return (p ? p->get() : nullptr); + } + private: + virtual nana::any* _m_anyobj(bool allocate_if_empty) const = 0; + }; + + /// The Any Objective is an object that may attach to some other object. + template + class any_objective + { + public: + typedef IndexType anyobj_index_t; ///< The type of index. It is available if Dimension is greater than 0. + + virtual ~any_objective(){} + + template + void anyobj(anyobj_index_t i, const Target& t) + { + nana::any * p = _m_anyobj(i, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist."); + *p = t; + } + + template + void anyobj(anyobj_index_t i, Target&& t) + { + nana::any * p = _m_anyobj(i, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + *p = std::move(t); + } + + template + Target * anyobj(anyobj_index_t i) const ///< Retrieves the attached object. Returns a nullptr if empty or if the type not match. + { + nana::any * p = _m_anyobj(i, false); + return (p ? p->get() : nullptr); + } + private: + virtual nana::any* _m_anyobj(anyobj_index_t i, bool allocate_if_empty) const = 0; + }; + + /// The Any Objective is an object that may attach to some other object. + template + class any_objective + { + public: + typedef IndexType anyobj_index_t; + + virtual ~any_objective(){} + + template + void anyobj(anyobj_index_t i0, anyobj_index_t i1, const Target& t) + { + nana::any * p = _m_anyobj(i0, i1, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + + *p = t; + } + + template + void anyobj(anyobj_index_t i0, anyobj_index_t i1, Target&& t) + { + nana::any * p = _m_anyobj(i0, i1, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + *p = std::move(t); + } + + template + Target * anyobj(anyobj_index_t i0, anyobj_index_t i1) const ///< Retrieves the attached object. Returns a nullptr if empty or if the type not match. + { + nana::any * p = _m_anyobj(i0, i1, false); + return (p ? p->get() : nullptr); + } + private: + virtual nana::any* _m_anyobj(anyobj_index_t i0, anyobj_index_t i1, bool allocate_if_empty) const = 0; + }; + }//end namespace concepts +}//end namespace nana +#endif diff --git a/include/nana/config.hpp b/include/nana/config.hpp new file mode 100644 index 00000000..8c25d372 --- /dev/null +++ b/include/nana/config.hpp @@ -0,0 +1,62 @@ +/* + * Nana Configuration + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/config.hpp + */ + +#ifndef NANA_CONFIG_HPP +#define NANA_CONFIG_HPP + +//Select platform automatically +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +//Windows: + #define NANA_WINDOWS 1 + #define PLATFORM_SPEC_HPP + #define GUI_BEDROCK_HPP + + //Test if it is MINGW + #if defined(__MINGW32__) + #define NANA_MINGW + #define STD_CODECVT_NOT_SUPPORTED + //#define STD_THREAD_NOT_SUPPORTED //Use this flag if MinGW version is older than 4.8.1 + #endif +#elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) +//Linux: + #define NANA_LINUX 1 + #define NANA_X11 1 + #define PLATFORM_SPEC_HPP + #define GUI_BEDROCK_HPP + + #define STD_CODECVT_NOT_SUPPORTED +#endif + +//Here defines some flags that tell Nana what features will be supported. + +#define NANA_UNICODE + +#if defined(NANA_UNICODE) && defined(NANA_WINDOWS) + #ifndef _UNICODE + #define _UNICODE + #endif + + #ifndef UNICODE + #define UNICODE + #endif +#endif + +//Support for PNG +// Comment it to disable the feature of support for PNG. +//#define NANA_ENABLE_PNG +#if defined(NANA_ENABLE_PNG) + //Comment it to use libpng from operating system. + #define NANA_LIBPNG +#endif + + +#endif //NANA_CONFIG_HPP diff --git a/include/nana/datetime.hpp b/include/nana/datetime.hpp new file mode 100644 index 00000000..6b9dd4e8 --- /dev/null +++ b/include/nana/datetime.hpp @@ -0,0 +1,75 @@ +/* + * A Date Time Implementation + * Copyright(C) 2003-2013 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/datetime.hpp + */ + +#ifndef NANA_DATETIME_HPP +#define NANA_DATETIME_HPP +#include + +namespace nana +{ + /// A date operation class. \see nana::date_chooser + class date + { + public: + struct value + { + unsigned year; ///< 1601 - 30827 + unsigned month; ///< 1-12 + unsigned day; ///< 1-31 + }; + + date(); ///< the initialized date is today. + date(const std::tm&); + date(int year, int month, int day); + + date operator - (int off) const; + date operator + (int off) const; + bool operator==(const date&) const; + bool operator!=(const date&) const; + bool operator<(const date&) const; + bool operator>(const date&) const; + bool operator<=(const date&) const; + bool operator>=(const date&) const; + + int day_of_week() const; + const value & read() const; + + static int day_of_week(int year, int month, int day); + static unsigned year_days(unsigned year); ///< the number of days in the specified year. + static unsigned month_days(unsigned year, unsigned month); ///< the number of days in the specified month. + static unsigned day_in_year(unsigned y, unsigned m, unsigned d); ///< Returns the index of the specified day in this year, at range[1, 365] or [1, 366] + private: + date _m_add(unsigned x) const; + date _m_sub(unsigned x) const; + private: + value value_; + }; //end class date + + class time + { + public: + struct value + { + unsigned hour; ///<[0-23] + unsigned minute; ///<[0-59] + unsigned second; ///<[0-61], the range of [60, 61] is used for leap seconds + }; + + time(); + time(const std::tm&); + time(unsigned hour, unsigned minute, unsigned second); + const value& read() const; + private: + value value_; + };//end class time +}//end namespace nana + +#endif diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp new file mode 100644 index 00000000..66fe0cfe --- /dev/null +++ b/include/nana/deploy.hpp @@ -0,0 +1,67 @@ +/* + * The Deploy Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/deploy.hpp + * + * What follow are dependented on what defined in nana/config.hpp + */ + +#ifndef NANA_DEPLOY_HPP +#define NANA_DEPLOY_HPP + +#include +#include +#if defined(NANA_LINUX) +#undef NANA_WINDOWS +#endif + +#ifndef NANA_UNICODE + namespace nana + { + typedef char char_t; + typedef std::string string; ///< An alias of std::wstring or std::string, depending on the macro NANA_UNICODE + } + #define STR(string) string +#else + namespace nana + { + typedef wchar_t char_t; + typedef std::wstring string; ///< An alias of std::wstring or std::string, depending on the macro NANA_UNICODE + } + #define STR(string) L##string +#endif + +namespace nana +{ + std::size_t strlen(const char_t* str); + double strtod(const char_t* str, char_t** endptr); + char_t* strcpy(char_t* dest, const char_t* source); +} + +#if defined(NANA_WINDOWS) + #define NANA_SHARED_EXPORT extern "C" _declspec(dllexport) +#elif defined(NANA_LINUX) + #define NANA_SHARED_EXPORT extern "C" +#endif + +namespace nana +{ + bool is_incomplete(const nana::string& str, unsigned pos); + + inline unsigned make_rgb(unsigned char red, unsigned char green, unsigned char blue) + { + + return ((unsigned(red) << 16)|((unsigned(green)<<8))|blue); + } +} + +#define NANA_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) + + +#endif //NANA_MACROS_HPP diff --git a/include/nana/detail/linux_X11/msg_dispatcher.hpp b/include/nana/detail/linux_X11/msg_dispatcher.hpp new file mode 100644 index 00000000..a1ca507c --- /dev/null +++ b/include/nana/detail/linux_X11/msg_dispatcher.hpp @@ -0,0 +1,341 @@ +/* + * Message Dispatcher Implementation + * Copyright(C) 2003-2013 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/detail/msg_dispatcher.hpp + * + * @DO NOT INCLUDE THIS HEADER FILE IN YOUR SOURCE FILE!! + * + * This class msg_dispatcher provides a simulation of Windows-like message + * dispatcher. Every event is dispatched into its own message queue for + * corresponding thread. + */ + +#ifndef NANA_DETAIL_MSG_DISPATCHER_HPP +#define NANA_DETAIL_MSG_DISPATCHER_HPP +#include "msg_packet.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nana +{ +namespace detail +{ + class msg_dispatcher + { + struct thread_binder + { + unsigned tid; + std::mutex mutex; + std::condition_variable cond; + std::list msg_queue; + std::set window; + }; + + public: + typedef msg_packet_tag msg_packet; + typedef void (*timer_proc_type)(unsigned tid); + typedef void (*event_proc_type)(Display*, msg_packet_tag&); + typedef int (*event_filter_type)(XEvent&, msg_packet_tag&); + + typedef std::list msg_queue_type; + + msg_dispatcher(Display* disp) + : display_(disp), is_work_(false) + { + proc_.event_proc = 0; + proc_.timer_proc = 0; + proc_.filter_proc = 0; + } + + void set(timer_proc_type timer_proc, event_proc_type event_proc, event_filter_type filter) + { + proc_.timer_proc = timer_proc; + proc_.event_proc = event_proc; + proc_.filter_proc = filter; + } + + void insert(Window wd) + { + unsigned tid = nana::system::this_thread_id(); + + bool start_driver; + + { + std::lock_guard lock(table_.mutex); + + //No thread is running, so msg dispatcher should start the msg driver. + start_driver = (0 == table_.thr_table.size()); + thread_binder * thr; + + std::map::iterator i = table_.thr_table.find(tid); + if(i == table_.thr_table.end()) + { + thr = new thread_binder; + thr->tid = tid; + table_.thr_table.insert(std::make_pair(tid, thr)); + } + else + thr = i->second; + + thr->mutex.lock(); + thr->window.insert(wd); + thr->mutex.unlock(); + + table_.wnd_table[wd] = thr; + } + + if(start_driver && proc_.event_proc && proc_.timer_proc) + { + //It should start the msg driver, before starting it, the msg driver must be inactive. + if(thrd_) + { + is_work_ = false; + thrd_->join(); + } + is_work_ = true; + thrd_ = std::unique_ptr(new std::thread([this](){ this->_m_msg_driver(); })); + } + } + + void erase(Window wd) + { + std::lock_guard lock(table_.mutex); + + auto i = table_.wnd_table.find(wd); + if(i != table_.wnd_table.end()) + { + thread_binder * const thr = i->second; + std::lock_guardmutex)> lock(thr->mutex); + for(auto li = thr->msg_queue.begin(); li != thr->msg_queue.end();) + { + if(wd == _m_window(*li)) + li = thr->msg_queue.erase(li); + else + ++li; + } + + table_.wnd_table.erase(i); + thr->window.erase(wd); + + //There still is at least one window alive. + if(thr->window.size()) + { + //Make a cleanup msg packet to infor the dispatcher the window is closed. + msg_packet_tag msg; + msg.kind = msg.kind_cleanup; + msg.u.packet_window = wd; + thr->msg_queue.push_back(msg); + } + } + } + + void dispatch(Window modal) + { + unsigned tid = nana::system::this_thread_id(); + msg_packet_tag msg; + int qstate; + + //Test whether the thread is registered for window, and retrieve the queue state for event + while((qstate = _m_read_queue(tid, msg, modal))) + { + //the queue is empty + if(-1 == qstate) + { + if(false == _m_wait_for_queue(tid)) + proc_.timer_proc(tid); + } + else + { + proc_.event_proc(display_, msg); + } + } + } + private: + void _m_msg_driver() + { + int fd_X11 = ConnectionNumber(display_); + + msg_packet_tag msg_pack; + XEvent event; + while(is_work_) + { + int pending; + { + nana::detail::platform_scope_guard psg; + pending = ::XPending(display_); + if(pending) + { + ::XNextEvent(display_, &event); + if(::XFilterEvent(&event, None)) + continue; + } + } + + if(0 == pending) + { + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(fd_X11, &fdset); + + struct timeval tv; + tv.tv_usec = 10000; + tv.tv_sec = 0; + ::select(fd_X11 + 1, &fdset, 0, 0, &tv); + } + else + { + switch(proc_.filter_proc(event, msg_pack)) + { + case 0: + msg_pack.kind = msg_pack.kind_xevent; + msg_pack.u.xevent = event; + case 1: + _m_msg_dispatch(msg_pack); + } + } + } + } + private: + static Window _m_event_window(const XEvent& event) + { + switch(event.type) + { + case MapNotify: + case UnmapNotify: + return event.xmap.window; + } + return event.xkey.window; + } + + static Window _m_window(const msg_packet_tag& pack) + { + switch(pack.kind) + { + case msg_packet_tag::kind_xevent: + return _m_event_window(pack.u.xevent); + case msg_packet_tag::kind_mouse_drop: + return pack.u.mouse_drop.window; + default: + break; + } + return 0; + } + + void _m_msg_dispatch(const msg_packet_tag &msg) + { + std::lock_guard lock(table_.mutex); + auto i = table_.wnd_table.find(_m_window(msg)); + if(i != table_.wnd_table.end()) + { + thread_binder * const thr = i->second; + + std::lock_guardmutex)> lock(thr->mutex); + thr->msg_queue.push_back(msg); + thr->cond.notify_one(); + } + } + + //_m_read_queue + //@brief:Read the event from a specified thread queue. + //@return: 0 = exit the queue, 1 = fetch the msg, -1 = no msg + int _m_read_queue(unsigned tid, msg_packet_tag& msg, Window modal) + { + bool stop_driver = false; + + { + std::lock_guard lock(table_.mutex); + //Find the thread whether it is registered for the window. + auto i = table_.thr_table.find(tid); + if(i != table_.thr_table.end()) + { + if(i->second->window.size()) + { + msg_queue_type & queue = i->second->msg_queue; + if(queue.size()) + { + msg = queue.front(); + queue.pop_front(); + + //Check whether the event dispatcher is used for the modal window + //and when the modal window is closing, the event dispatcher would + //stop event pumping. + if((modal == msg.u.packet_window) && (msg.kind == msg.kind_cleanup)) + return 0; + + return 1; + } + else + return -1; + } + + delete i->second; + table_.thr_table.erase(i); + stop_driver = (table_.thr_table.size() == 0); + } + } + if(stop_driver) + { + is_work_ = false; + thrd_->join(); + thrd_.reset(); + } + return 0; + } + + //_m_wait_for_queue + // wait for the insertion of queue. + //return@ it returns true if the queue is not empty, otherwise the wait is timeout. + bool _m_wait_for_queue(unsigned tid) + { + thread_binder * thr = nullptr; + { + std::lock_guard lock(table_.mutex); + auto i = table_.thr_table.find(tid); + if(i != table_.thr_table.end()) + { + if(i->second->msg_queue.size()) + return true; + thr = i->second; + } + } + + //Waits for notifying the condition variable, it indicates a new msg is pushing into the queue. + std::unique_lockmutex)> lock(thr->mutex); + return (thr->cond.wait_for(lock, std::chrono::milliseconds(10)) != std::cv_status::timeout); + } + + private: + Display * display_; + volatile bool is_work_; + std::unique_ptr thrd_; + + struct table_tag + { + std::recursive_mutex mutex; + std::map thr_table; + std::map wnd_table; + }table_; + + struct proc_tag + { + timer_proc_type timer_proc; + event_proc_type event_proc; + event_filter_type filter_proc; + }proc_; + }; +}//end namespace detail +}//end namespace nana + +#endif + diff --git a/include/nana/detail/linux_X11/msg_packet.hpp b/include/nana/detail/linux_X11/msg_packet.hpp new file mode 100644 index 00000000..b1fc3dec --- /dev/null +++ b/include/nana/detail/linux_X11/msg_packet.hpp @@ -0,0 +1,32 @@ +#ifndef NANA_DETAIL_MSG_PACKET_HPP +#define NANA_DETAIL_MSG_PACKET_HPP +#include +#include +#include + +namespace nana +{ +namespace detail +{ + struct msg_packet_tag + { + enum kind_t{kind_xevent, kind_mouse_drop, kind_cleanup}; + kind_t kind; + union + { + XEvent xevent; + + Window packet_window; //Avaiable if the packet is not kind_xevent + struct mouse_drop_tag + { + Window window; + int x; + int y; + std::vector * files; + }mouse_drop; + }u; + }; +}//end namespace detail +}//end namespace nana +#endif + diff --git a/include/nana/detail/linux_X11/platform_spec.hpp b/include/nana/detail/linux_X11/platform_spec.hpp new file mode 100644 index 00000000..f9914ecd --- /dev/null +++ b/include/nana/detail/linux_X11/platform_spec.hpp @@ -0,0 +1,317 @@ +/* + * Platform Specification Implementation + * Copyright(C) 2003-2013 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/detail/platform_spec.hpp + * + * This file provides basis class and data structrue that required by nana + * This file should not be included by any header files. + */ + +#ifndef NANA_DETAIL_PLATFORM_SPEC_HPP +#define NANA_DETAIL_PLATFORM_SPEC_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "msg_packet.hpp" +#if defined(NANA_UNICODE) + #include + #include + #include +#endif + +namespace nana +{ +namespace detail +{ + class msg_dispatcher; +#if defined(NANA_UNICODE) + class conf + { + public: + conf(const char * file); + bool open(const char* file); + std::string value(const char* key); + private: + std::ifstream ifs_; + }; + + class charset_conv + { + public: + charset_conv(const char* tocode, const char* fromcode); + ~charset_conv(); + std::string charset(const std::string& str) const; + std::string charset(const char * buf, std::size_t len) const; + private: + iconv_t handle_; + }; +#endif + + struct font_tag + { + nana::string name; + unsigned height; + unsigned weight; + bool italic; + bool underline; + bool strikeout; +#if defined(NANA_UNICODE) + XftFont * handle; +#else + XFontSet handle; +#endif + }; + + struct drawable_impl_type + { + typedef std::shared_ptr font_ptr_t; + + drawable_impl_type(); + ~drawable_impl_type(); + + void fgcolor(unsigned color); + + Pixmap pixmap; + GC context; + font_ptr_t font; + + nana::point line_begin_pos; + + struct string_spec + { + unsigned tab_length; + unsigned tab_pixels; + unsigned whitespace_pixels; + }string; +#if defined(NANA_UNICODE) + XftDraw * xftdraw; + XftColor xft_fgcolor; + XftColor xft_bgcolor; + const std::string charset(const nana::string& str, const std::string& strcode); +#endif + private: + unsigned fgcolor_; +#if defined(NANA_UNICODE) + struct conv_tag + { + iconv_t handle; + std::string code; + }conv_; +#endif + }; + + struct atombase_tag + { + Atom wm_protocols; + //window manager support + Atom wm_change_state; + Atom wm_delete_window; + //ext + Atom net_wm_state; + Atom net_wm_state_skip_taskbar; + Atom net_wm_state_fullscreen; + Atom net_wm_state_maximized_horz; + Atom net_wm_state_maximized_vert; + Atom net_wm_state_modal; + Atom net_wm_window_type; + Atom net_wm_window_type_normal; + Atom net_wm_window_type_utility; + Atom net_wm_window_type_dialog; + Atom motif_wm_hints; + + Atom clipboard; + Atom text; + Atom text_uri_list; + Atom utf8_string; + Atom targets; + + Atom xdnd_aware; + Atom xdnd_enter; + Atom xdnd_position; + Atom xdnd_status; + Atom xdnd_action_copy; + Atom xdnd_drop; + Atom xdnd_selection; + Atom xdnd_typelist; + Atom xdnd_finished; + }; + + struct caret_tag; + + class timer_runner; + + class platform_scope_guard + { + public: + platform_scope_guard(); + ~platform_scope_guard(); + }; + + class platform_spec + { + typedef platform_spec self_type; + + struct window_context_t + { + native_window_type owner; + std::vector * owned; + }; + public: + int error_code; + public: + typedef drawable_impl_type::font_ptr_t font_ptr_t; + typedef void (*timer_proc_type)(unsigned tid); + typedef void (*event_proc_type)(Display*, msg_packet_tag&); + typedef ::nana::event_code event_code; + typedef ::nana::native_window_type native_window_type; + + + platform_spec(); + ~platform_spec(); + + const font_ptr_t& default_native_font() const; + void default_native_font(const font_ptr_t&); + unsigned font_size_to_height(unsigned) const; + unsigned font_height_to_size(unsigned) const; + font_ptr_t make_native_font(const nana::char_t* name, unsigned height, unsigned weight, bool italic, bool underline, bool strick_out); + + Display* open_display(); + void close_display(); + + void lock_xlib(); + void unlock_xlib(); + + Window root_window(); + int screen_depth(); + Visual* screen_visual(); + + Colormap& colormap(); + + static self_type& instance(); + const atombase_tag & atombase() const; + + void make_owner(native_window_type owner, native_window_type wd); + native_window_type get_owner(native_window_type) const; + void remove(native_window_type); + + void write_keystate(const XKeyEvent&); + void read_keystate(XKeyEvent&); + + XIC caret_input_context(native_window_type) const; + void caret_open(native_window_type, unsigned width, unsigned height); + void caret_close(native_window_type); + void caret_pos(native_window_type, int x, int y); + void caret_visible(native_window_type, bool); + void caret_flash(caret_tag&); + bool caret_update(native_window_type, nana::paint::graphics& root_graph, bool is_erase_caret_from_root_graph); + static bool caret_reinstate(caret_tag&); + void set_error_handler(); + int rev_error_handler(); + + //grab + //register a grab window while capturing it if it is unviewable. + //when native_interface::show a window that is registered as a grab + //window, the native_interface grabs the window. + Window grab(Window); + void set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t id)); + void kill_timer(std::size_t id); + void timer_proc(unsigned tid); + + //Message dispatcher + void msg_insert(native_window_type); + void msg_set(timer_proc_type, event_proc_type); + void msg_dispatch(native_window_type modal); + + //X Selections + void* request_selection(native_window_type requester, Atom type, size_t & bufsize); + void write_selection(native_window_type owner, Atom type, const void* buf, size_t bufsize); + + //Icon storage + //@biref: The image object should be kept for a long time till the window is closed, + // the image object is release in remove() method. + const nana::paint::graphics& keep_window_icon(native_window_type, const nana::paint::image&); + private: + static int _m_msg_filter(XEvent&, msg_packet_tag&); + void _m_caret_routine(); + private: + Display* display_; + Colormap colormap_; + atombase_tag atombase_; + font_ptr_t def_font_ptr_; + XKeyEvent key_state_; + int (*def_X11_error_handler_)(Display*, XErrorEvent*); + Window grab_; + std::recursive_mutex xlib_locker_; + struct caret_holder_tag + { + volatile bool exit_thread; + std::unique_ptr thr; + std::map carets; + }caret_holder_; + + std::map wincontext_; + std::map iconbase_; + + struct timer_runner_tag + { + timer_runner * runner; + std::recursive_mutex mutex; + bool delete_declared; + timer_runner_tag(); + }timer_; + + struct selection_tag + { + struct item_t + { + Atom type; + Window requestor; + void* buffer; + size_t bufsize; + std::mutex cond_mutex; + std::condition_variable cond; + }; + + std::vector items; + + struct content_tag + { + std::string * utf8_string; + }content; + }selection_; + + struct xdnd_tag + { + Atom good_type; + int timestamp; + Window wd_src; + nana::point pos; + }xdnd_; + + msg_dispatcher * msg_dispatcher_; + };//end class platform_X11 + +}//end namespace detail + +}//end namespace nana + +#endif + diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp new file mode 100644 index 00000000..cb4be1fd --- /dev/null +++ b/include/nana/detail/win32/platform_spec.hpp @@ -0,0 +1,179 @@ +/* + * Platform Specification Implementation + * Copyright(C) 2003-2013 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/detail/platform_spec.hpp + * + * This file provides basis class and data structrue that required by nana + * This file should not be included by any header files. + */ + +#ifndef NANA_DETAIL_PLATFORM_SPEC_HPP +#define NANA_DETAIL_PLATFORM_SPEC_HPP + +#include +#include +#include +#include + +#include +#include +#include + +namespace nana +{ + +namespace detail +{ + //struct messages + //@brief: This defines some messages that are used for remote thread invocation. + // Some Windows APIs are window-thread-dependent, the operation in other thread + // must be posted to its own thread. + struct messages + { + struct caret + { + int x; + int y; + unsigned width; + unsigned height; + bool visible; + }; + + struct move_window + { + enum { Pos = 1, Size = 2}; + int x; + int y; + unsigned width; + unsigned height; + unsigned ignore; //determinate that pos or size would be ignored. + }; + + enum + { + tray = 0x501, + async_activate, + async_set_focus, + map_thread_root_buffer, + remote_thread_destroy_window, + remote_thread_move_window, + operate_caret, //wParam: 1=Destroy, 2=SetPos + remote_thread_set_window_pos, + remote_thread_set_window_text, + user, + }; + }; + + struct font_tag + { + nana::string name; + unsigned height; + unsigned weight; + bool italic; + bool underline; + bool strikeout; + HFONT handle; + + struct deleter + { + void operator()(const font_tag*) const; + }; + }; + + struct drawable_impl_type + { + typedef std::shared_ptr font_ptr_t; + + HDC context; + HBITMAP pixmap; + pixel_rgb_t* pixbuf_ptr; + std::size_t bytes_per_line; + font_ptr_t font; + + struct pen_spec + { + HPEN handle; + unsigned color; + int style; + int width; + + void set(HDC context, int style, int width, nana::color_t color); + }pen; + + struct brush_spec + { + enum t{Solid, HatchBDiagonal}; + + HBRUSH handle; + t style; + nana::color_t color; + + void set(HDC context, t style, nana::color_t color); + }brush; + + struct round_region_spec + { + HRGN handle; + nana::rectangle r; + unsigned radius_x; + unsigned radius_y; + + void set(const nana::rectangle& r, unsigned radius_x, unsigned radius_y); + }round_region; + + struct string_spec + { + unsigned tab_length; + unsigned tab_pixels; + unsigned whitespace_pixels; + }string; + + drawable_impl_type(); + ~drawable_impl_type(); + + void fgcolor(nana::color_t); + private: + unsigned fgcolor_; + }; + + class platform_spec + { + public: + typedef drawable_impl_type::font_ptr_t font_ptr_t; + typedef ::nana::event_code event_code; + typedef ::nana::native_window_type native_window_type; + + class co_initializer + { + public: + co_initializer(); + ~co_initializer(); + private: + HMODULE ole32_; + }; + + platform_spec(); + + const font_ptr_t& default_native_font() const; + void default_native_font(const font_ptr_t&); + unsigned font_size_to_height(unsigned) const; + unsigned font_height_to_size(unsigned) const; + font_ptr_t make_native_font(const nana::char_t* name, unsigned height, unsigned weight, bool italic, bool underline, bool strike_out); + + static platform_spec& instance(); + + void keep_window_icon(native_window_type, const nana::paint::image&); + void release_window_icon(native_window_type); + private: + font_ptr_t def_font_ptr_; + std::map iconbase_; + }; + +}//end namespace detail +}//end namespace nana +#endif diff --git a/include/nana/exceptions.hpp b/include/nana/exceptions.hpp new file mode 100644 index 00000000..c1f709f4 --- /dev/null +++ b/include/nana/exceptions.hpp @@ -0,0 +1,95 @@ +/* + * Exception Definition + * Copyright(C) 2003-2013 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/exceptions.hpp + */ + +#ifndef NANA_EXCEPTIONS_H +#define NANA_EXCEPTIONS_H +#include +#include + +namespace nana +{ + + /** + * nana::threads::thread::exit throws this exception to exit thread + * this exception is not allowed to be catch by programmer, + * otherwise the thread may not exit + */ + class thrd_exit: public std::exception + { + public: + thrd_exit(unsigned retval); + ~thrd_exit() throw(); + const char* what() const throw(); + unsigned retval() const; + private: + unsigned retval_; + }; + + /** + * nana::text::settings_t throws this exception if it dose not found a given member + * in a scope + */ + class bad_member: public std::exception + { + public: + bad_member(const std::string& what); + ~bad_member() throw(); + const char* what() const throw(); + private: + std::string what_; + }; + + /** + * nana::text::settings_t throws this exception if there is a syntax error + */ + class bad_syntax: public std::exception + { + public: + bad_syntax(const std::string& what); + ~bad_syntax() throw(); + const char* what() const throw(); + private: + std::string what_; + }; + + class bad_error: public std::exception + { + public: + bad_error(const std::string& what); + ~bad_error() throw(); + const char* what() const throw(); + private: + std::string what_; + }; + + class bad_handle: public std::exception + { + public: + bad_handle(const std::string& what); + ~bad_handle() throw(); + const char* what() const throw(); + private: + std::string what_; + }; + + class bad_window + :public std::exception + { + public: + bad_window(const char* what); + ~bad_window() throw(); + const char* what() const throw(); + private: + std::string what_; + }; +}// end namespace nana + +#endif diff --git a/include/nana/extrlib/png.h b/include/nana/extrlib/png.h new file mode 100644 index 00000000..bebaf549 --- /dev/null +++ b/include/nana/extrlib/png.h @@ -0,0 +1,2654 @@ + +/* png.h - header file for PNG reference library + * + * libpng version 1.5.8 - February 1, 2012 + * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license (See LICENSE, below) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.5.8 - February 1, 2012: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + * 1.2.9beta4-11 13 10209 12.so.0.9[.0] + * 1.2.9rc1 13 10209 12.so.0.9[.0] + * 1.2.9 13 10209 12.so.0.9[.0] + * 1.2.10beta1-7 13 10210 12.so.0.10[.0] + * 1.2.10rc1-2 13 10210 12.so.0.10[.0] + * 1.2.10 13 10210 12.so.0.10[.0] + * 1.4.0beta1-5 14 10400 14.so.0.0[.0] + * 1.2.11beta1-4 13 10211 12.so.0.11[.0] + * 1.4.0beta7-8 14 10400 14.so.0.0[.0] + * 1.2.11 13 10211 12.so.0.11[.0] + * 1.2.12 13 10212 12.so.0.12[.0] + * 1.4.0beta9-14 14 10400 14.so.0.0[.0] + * 1.2.13 13 10213 12.so.0.13[.0] + * 1.4.0beta15-36 14 10400 14.so.0.0[.0] + * 1.4.0beta37-87 14 10400 14.so.14.0[.0] + * 1.4.0rc01 14 10400 14.so.14.0[.0] + * 1.4.0beta88-109 14 10400 14.so.14.0[.0] + * 1.4.0rc02-08 14 10400 14.so.14.0[.0] + * 1.4.0 14 10400 14.so.14.0[.0] + * 1.4.1beta01-03 14 10401 14.so.14.1[.0] + * 1.4.1rc01 14 10401 14.so.14.1[.0] + * 1.4.1beta04-12 14 10401 14.so.14.1[.0] + * 1.4.1 14 10401 14.so.14.1[.0] + * 1.4.2 14 10402 14.so.14.2[.0] + * 1.4.3 14 10403 14.so.14.3[.0] + * 1.4.4 14 10404 14.so.14.4[.0] + * 1.5.0beta01-58 15 10500 15.so.15.0[.0] + * 1.5.0rc01-07 15 10500 15.so.15.0[.0] + * 1.5.0 15 10500 15.so.15.0[.0] + * 1.5.1beta01-11 15 10501 15.so.15.1[.0] + * 1.5.1rc01-02 15 10501 15.so.15.1[.0] + * 1.5.1 15 10501 15.so.15.1[.0] + * 1.5.2beta01-03 15 10502 15.so.15.2[.0] + * 1.5.2rc01-03 15 10502 15.so.15.2[.0] + * 1.5.2 15 10502 15.so.15.2[.0] + * 1.5.3beta01-10 15 10503 15.so.15.3[.0] + * 1.5.3rc01-02 15 10503 15.so.15.3[.0] + * 1.5.3beta11 15 10503 15.so.15.3[.0] + * 1.5.3 [omitted] + * 1.5.4beta01-08 15 10504 15.so.15.4[.0] + * 1.5.4rc01 15 10504 15.so.15.4[.0] + * 1.5.4 15 10504 15.so.15.4[.0] + * 1.5.5beta01-08 15 10505 15.so.15.5[.0] + * 1.5.5rc01 15 10505 15.so.15.5[.0] + * 1.5.5 15 10505 15.so.15.5[.0] + * 1.5.6beta01-07 15 10506 15.so.15.6[.0] + * 1.5.6rc01-03 15 10506 15.so.15.6[.0] + * 1.5.6 15 10506 15.so.15.6[.0] + * 1.5.7beta01-05 15 10507 15.so.15.7[.0] + * 1.5.7rc01-03 15 10507 15.so.15.7[.0] + * 1.5.7 15 10507 15.so.15.7[.0] + * 1.5.8beta01 15 10508 15.so.15.8[.0] + * 1.5.8rc01 15 10508 15.so.15.8[.0] + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng-manual.txt or libpng.3 for more information. The PNG + * specification is available as a W3C Recommendation and as an ISO + * Specification, +# endif + + /* Need the time information for converting tIME chunks, it + * defines struct tm: + */ +# ifdef PNG_CONVERT_tIME_SUPPORTED + /* "time.h" functions are not supported on all operating systems */ +# include +# endif +# endif + +/* Machine specific configuration. */ +# include "pngconf.h" +#endif + +/* + * Added at libpng-1.2.8 + * + * Ref MSDN: Private as priority over Special + * VS_FF_PRIVATEBUILD File *was not* built using standard release + * procedures. If this value is given, the StringFileInfo block must + * contain a PrivateBuild string. + * + * VS_FF_SPECIALBUILD File *was* built by the original company using + * standard release procedures but is a variation of the standard + * file of the same version number. If this value is given, the + * StringFileInfo block must contain a SpecialBuild string. + */ + +#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */ +# define PNG_LIBPNG_BUILD_TYPE \ + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE) +#else +# ifdef PNG_LIBPNG_SPECIALBUILD +# define PNG_LIBPNG_BUILD_TYPE \ + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL) +# else +# define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE) +# endif +#endif + +#ifndef PNG_VERSION_INFO_ONLY + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#define png_libpng_ver png_get_header_ver(NULL) + +/* This file is arranged in several sections: + * + * 1. Any configuration options that can be specified by for the application + * code when it is built. (Build time configuration is in pnglibconf.h) + * 2. Type definitions (base types are defined in pngconf.h), structure + * definitions. + * 3. Exported library functions. + * + * The library source code has additional files (principally pngpriv.h) that + * allow configuration of the library. + */ +/* Section 1: run time configuration + * See pnglibconf.h for build time configuration + * + * Run time configuration allows the application to choose between + * implementations of certain arithmetic APIs. The default is set + * at build time and recorded in pnglibconf.h, but it is safe to + * override these (and only these) settings. Note that this won't + * change what the library does, only application code, and the + * settings can (and probably should) be made on a per-file basis + * by setting the #defines before including png.h + * + * Use macros to read integers from PNG data or use the exported + * functions? + * PNG_USE_READ_MACROS: use the macros (see below) Note that + * the macros evaluate their argument multiple times. + * PNG_NO_USE_READ_MACROS: call the relevant library function. + * + * Use the alternative algorithm for compositing alpha samples that + * does not use division? + * PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division' + * algorithm. + * PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm. + * + * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is + * false? + * PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error + * APIs to png_warning. + * Otherwise the calls are mapped to png_error. + */ + +/* Section 2: type definitions, including structures and compile time + * constants. + * See pngconf.h for base types that vary by machine/system + */ + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef char* png_libpng_version_1_5_8; + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color FAR * png_colorp; +typedef PNG_CONST png_color FAR * png_const_colorp; +typedef png_color FAR * FAR * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 FAR * png_color_16p; +typedef PNG_CONST png_color_16 FAR * png_const_color_16p; +typedef png_color_16 FAR * FAR * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 FAR * png_color_8p; +typedef PNG_CONST png_color_8 FAR * png_const_color_8p; +typedef png_color_8 FAR * FAR * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry FAR * png_sPLT_entryp; +typedef PNG_CONST png_sPLT_entry FAR * png_const_sPLT_entryp; +typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t FAR * png_sPLT_tp; +typedef PNG_CONST png_sPLT_t FAR * png_const_sPLT_tp; +typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text" fields can be a + * regular C string, an empty string, or a NULL pointer. + * However, the structure returned by png_get_text() will always contain + * the "text" field as a regular zero-terminated C string (possibly + * empty), never a NULL pointer, so it can be safely used in printf() and + * other string-handling functions. Note that the "itxt_length", "lang", and + * "lang_key" members of the structure only exist when the library is built + * with iTXt chunk support. Prior to libpng-1.4.0 the library was built by + * default without iTXt support. Also note that when iTXt *is* supported, + * the "lang" and "lang_key" fields contain NULL pointers when the + * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or + * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the + * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag" + * which is always 0 or 1, or its "compression method" which is always 0. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +} png_text; +typedef png_text FAR * png_textp; +typedef PNG_CONST png_text FAR * png_const_textp; +typedef png_text FAR * FAR * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time FAR * png_timep; +typedef PNG_CONST png_time FAR * png_const_timep; +typedef png_time FAR * FAR * png_timepp; + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) || \ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} + + +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef PNG_CONST png_unknown_chunk FAR * png_const_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; +#endif + +/* Values for the unknown chunk location byte */ + +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_AFTER_IDAT 0x08 + +/* The complete definition of png_info has, as of libpng-1.5.0, + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_info_def png_info; +typedef png_info FAR * png_infop; +typedef PNG_CONST png_info FAR * png_const_infop; +typedef png_info FAR * FAR * png_infopp; + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) +#define PNG_UINT_32_MAX ((png_uint_32)(-1)) +#define PNG_SIZE_MAX ((png_size_t)(-1)) + +/* These are constants for fixed point values encoded in the + * PNG specification manner (x100000) + */ +#define PNG_FP_1 100000 +#define PNG_FP_HALF 50000 +#define PNG_FP_MAX ((png_fixed_point)0x7fffffffL) +#define PNG_FP_MIN (-PNG_FP_MAX) + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_ defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_size_t rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* The complete definition of png_struct has, as of libpng-1.5.0, + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_struct_def png_struct; +typedef PNG_CONST png_struct FAR * png_const_structp; +typedef png_struct FAR * png_structp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. Note that the 'write' function must not + * modify the buffer it is passed. The 'read' function, on the other hand, is + * expected to return the read data in the buffer. + */ +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); + +/* The following callback receives png_uint_32 row_number, int pass for the + * png_bytep data of the row. When transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. + * + * If you get a warning here while building the library you may need to make + * changes to ensure that pnglibconf.h records the calling convention used by + * your compiler. This may be very difficult - try using a different compiler + * to build the library! + */ +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.4.0 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +/* NOTE: prior to 1.5 these functions had no 'API' style declaration, + * this allowed the zlib default functions to be used on Windows + * platforms. In 1.5 the zlib default malloc (which just calls malloc and + * ignores the first argument) should be completely compatible with the + * following. + */ +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); + +typedef png_struct FAR * FAR * png_structpp; + +/* Section 3: exported functions + * Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng-manual.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + * + * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in + * pngconf.h and in the *.dfn files in the scripts directory. + * + * PNG_EXPORT(ordinal, type, name, (args)); + * + * ordinal: ordinal that is used while building + * *.def files. The ordinal value is only + * relevant when preprocessing png.h with + * the *.dfn files for building symbol table + * entries, and are removed by pngconf.h. + * type: return type of the function + * name: function name + * args: function arguments, with types + * + * When we wish to append attributes to a function prototype we use + * the PNG_EXPORTA() macro instead. + * + * PNG_EXPORTA(ordinal, type, name, (args), attributes); + * + * ordinal, type, name, and args: same as in PNG_EXPORT(). + * attributes: function attributes + */ + +/* Returns the version number of the library */ +PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structp png_ptr, int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +PNG_EXPORTA(4, png_structp, png_create_read_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +PNG_EXPORTA(5, png_structp, png_create_write_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); + +PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, + (png_const_structp png_ptr)); + +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structp png_ptr, + png_size_t size)); + +/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp + * match up. + */ +#ifdef PNG_SETJMP_SUPPORTED +/* This function returns the jmp_buf built in to *png_ptr. It must be + * supplied with an appropriate 'longjmp' function to use on that jmp_buf + * unless the default error function is overridden in which case NULL is + * acceptable. The size of the jmp_buf is checked against the actual size + * allocated by the library - the call will return NULL on a mismatch + * indicating an ABI mismatch. + */ +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); +# define png_jmpbuf(png_ptr) \ + (*png_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) +#endif +/* This function should be used by libpng applications in place of + * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it + * will use it; otherwise it will call PNG_ABORT(). This function was + * added in libpng-1.5.0. + */ +PNG_EXPORTA(9, void, png_longjmp, (png_structp png_ptr, int val), + PNG_NORETURN); + +#ifdef PNG_READ_SUPPORTED +/* Reset the compression stream */ +PNG_EXPORT(10, int, png_reset_zstream, (png_structp png_ptr)); +#endif + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(11, png_structp, png_create_read_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +PNG_EXPORTA(12, png_structp, png_create_write_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +#endif + +/* Write the PNG file signature. */ +PNG_EXPORT(13, void, png_write_sig, (png_structp png_ptr)); + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +PNG_EXPORT(14, void, png_write_chunk, (png_structp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +PNG_EXPORT(15, void, png_write_chunk_start, (png_structp png_ptr, + png_const_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +PNG_EXPORT(16, void, png_write_chunk_data, (png_structp png_ptr, + png_const_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +PNG_EXPORT(17, void, png_write_chunk_end, (png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_structp png_ptr), + PNG_ALLOCATED); + +PNG_EXPORT(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +PNG_EXPORT(20, void, png_write_info_before_PLTE, + (png_structp png_ptr, png_infop info_ptr)); +PNG_EXPORT(21, void, png_write_info, + (png_structp png_ptr, png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +PNG_EXPORT(22, void, png_read_info, + (png_structp png_ptr, png_infop info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +PNG_EXPORT(23, png_const_charp, png_convert_to_rfc1123, + (png_structp png_ptr, + png_const_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + PNG_CONST struct tm FAR * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +PNG_EXPORT(25, void, png_convert_from_time_t, + (png_timep ptime, time_t ttime)); +#endif /* PNG_CONVERT_tIME_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +PNG_EXPORT(26, void, png_set_expand, (png_structp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structp png_ptr)); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +PNG_EXPORT(30, void, png_set_bgr, (png_structp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#define PNG_ERROR_ACTION_NONE 1 +#define PNG_ERROR_ACTION_WARN 2 +#define PNG_ERROR_ACTION_ERROR 3 +#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ + +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structp png_ptr, + int error_action, double red, double green)); +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)); + +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structp + png_ptr)); +#endif + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels of + * a PNG file are returned when an alpha channel, or tRNS chunk in a palette + * file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel. The gamma encoded color channels must be + * scaled according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. The + * advantage is that the color channels can be resampled (the image can be + * scaled) in this form. The disadvantage is that normal practice is to store + * linear, not (gamma) encoded, values and this requires 16-bit channels for + * still images rather than the 8-bit channels that are just about sufficient if + * gamma encoding is used. In addition all non-transparent pixel values, + * including completely opaque ones, must be gamma encoded to produce the final + * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the + * latter being the two common names for associated alpha color channels.) + * + * Since it is not necessary to perform arithmetic on opaque color values so + * long as they are not to be resampled and are in the final color space it is + * possible to optimize the handling of alpha by storing the opaque pixels in + * the PNG format (adjusted for the output color space) while storing partially + * opaque pixels in the standard, linear, format. The accuracy required for + * standard alpha composition is relatively low, because the pixels are + * isolated, therefore typically the accuracy loss in storing 8-bit linear + * values is acceptable. (This is not true if the alpha channel is used to + * simulate transparency over large areas - use 16 bits or the PNG mode in + * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is + * treated as opaque only if the alpha value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structp png_ptr, int mode, + double output_gamma)); +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr, + int mode, png_fixed_point output_gamma)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. The values used + * correspond to the normal numbers used to describe the overall gamma of a + * computer display system; for example 2.2 for an sRGB conformant system. The + * values are scaled by 100000 in the _fixed version of the API (so 220000 for + * sRGB.) + * + * The inverse of the value is always used to provide a default for the PNG file + * encoding if it has no gAMA chunk and if png_set_gamma() has not been called + * to override the PNG gamma information. + * + * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode + * opaque pixels however pixels with lower alpha values are not encoded, + * regardless of the output gamma setting. + * + * When the standard Porter Duff handling is requested with mode 1 the output + * encoding is set to be linear and the output_gamma value is only relevant + * as a default for input data that has no gamma information. The linear output + * encoding will be overridden if png_set_gamma() is called - the results may be + * highly unexpected! + * + * The following numbers are derived from the sRGB standard and the research + * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of + * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing + * correction required to take account of any differences in the color + * environment of the original scene and the intended display environment; the + * value expresses how to *decode* the image for display, not how the original + * data was *encoded*. + * + * sRGB provides a peg for the PNG standard by defining a viewing environment. + * sRGB itself, and earlier TV standards, actually use a more complex transform + * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is + * limited to simple power laws.) By saying that an image for direct display on + * an sRGB conformant system should be stored with a gAMA chunk value of 45455 + * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification + * makes it possible to derive values for other display systems and + * environments. + * + * The Mac value is deduced from the sRGB based on an assumption that the actual + * extra viewing correction used in early Mac display systems was implemented as + * a power 1.45 lookup table. + * + * Any system where a programmable lookup table is used or where the behavior of + * the final display device characteristics can be changed requires system + * specific code to obtain the current characteristic. However this can be + * difficult and most PNG gamma correction only requires an approximate value. + * + * By default, if png_set_alpha_mode() is not called, libpng assumes that all + * values are unencoded, linear, values and that the output device also has a + * linear characteristic. This is only very rarely correct - it is invariably + * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the + * default if you don't know what the right answer is! + * + * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS + * 10.6) which used a correction table to implement a somewhat lower gamma on an + * otherwise sRGB system. + * + * Both these values are reserved (not simple gamma values) in order to allow + * more precise correction internally in the future. + * + * NOTE: the following values can be passed to either the fixed or floating + * point APIs, but the floating point API will also accept floating point + * values. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceeded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the ouput gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(39, void, png_set_filler, (png_structp png_ptr, png_uint_32 filler, + int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +# define PNG_FILLER_BEFORE 0 +# define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(40, void, png_set_add_alpha, + (png_structp png_ptr, png_uint_32 filler, + int flags)); +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +PNG_EXPORT(41, void, png_set_swap, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +PNG_EXPORT(42, void, png_set_packing, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +PNG_EXPORT(43, void, png_set_packswap, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +PNG_EXPORT(44, void, png_set_shift, (png_structp png_ptr, png_const_color_8p + true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. + * MUST be called before png_read_update_info or png_start_read_image, + * otherwise it will not have the desired effect. Note that it is still + * necessary to call png_read_row or png_read_rows png_get_image_height + * times for each pass. +*/ +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ +PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma)); +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED +# define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +# define PNG_BACKGROUND_GAMMA_SCREEN 1 +# define PNG_BACKGROUND_GAMMA_FILE 2 +# define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structp png_ptr)); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ +/* Strip the second byte of information from a 16-bit depth file. */ +PNG_EXPORT(48, void, png_set_strip_16, (png_structp png_ptr)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Turn on quantizing, and reduce the palette to the number of colors + * available. + */ +PNG_EXPORT(49, void, png_set_quantize, + (png_structp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_const_uint_16p histogram, + int full_quantize)); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The threshold on gamma processing is configurable but hard-wired into the + * library. The following is the floating point variant. + */ +#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) + +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ +PNG_FP_EXPORT(50, void, png_set_gamma, + (png_structp png_ptr, double screen_gamma, + double override_file_gamma)); +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)); +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +PNG_EXPORT(51, void, png_set_flush, (png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +PNG_EXPORT(52, void, png_write_flush, (png_structp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +PNG_EXPORT(53, void, png_start_read_image, (png_structp png_ptr)); + +/* Optional call to update the users info structure */ +PNG_EXPORT(54, void, png_read_update_info, + (png_structp png_ptr, png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +PNG_EXPORT(55, void, png_read_rows, (png_structp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +PNG_EXPORT(56, void, png_read_row, (png_structp png_ptr, png_bytep row, + png_bytep display_row)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +PNG_EXPORT(57, void, png_read_image, (png_structp png_ptr, png_bytepp image)); +#endif + +/* Write a row of image data */ +PNG_EXPORT(58, void, png_write_row, + (png_structp png_ptr, png_const_bytep row)); + +/* Write a few rows of image data: (*row) is not written; however, the type + * is declared as writeable to maintain compatibility with previous versions + * of libpng and to allow the 'display_row' array from read_rows to be passed + * unchanged to write_rows. + */ +PNG_EXPORT(59, void, png_write_rows, (png_structp png_ptr, png_bytepp row, + png_uint_32 num_rows)); + +/* Write the image data */ +PNG_EXPORT(60, void, png_write_image, + (png_structp png_ptr, png_bytepp image)); + +/* Write the end of the PNG file. */ +PNG_EXPORT(61, void, png_write_end, + (png_structp png_ptr, png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +PNG_EXPORT(62, void, png_read_end, (png_structp png_ptr, png_infop info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +PNG_EXPORT(63, void, png_destroy_info_struct, (png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); + +/* Set the libpng method of handling chunk CRC errors */ +PNG_EXPORT(66, void, png_set_crc_action, + (png_structp png_ptr, int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +PNG_EXPORT(67, void, png_set_filter, + (png_structp png_ptr, int method, int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs)); +PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, + (png_structp png_ptr, + int heuristic_method, int num_weights, png_const_fixed_point_p + filter_weights, png_const_fixed_point_p filter_costs)); +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +#ifdef PNG_WRITE_SUPPORTED +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +PNG_EXPORT(69, void, png_set_compression_level, + (png_structp png_ptr, int level)); + +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structp png_ptr, + int mem_level)); + +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structp png_ptr, + int window_bits)); + +PNG_EXPORT(73, void, png_set_compression_method, (png_structp png_ptr, + int method)); +#endif + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, + (png_structp png_ptr, int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structp + png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr, + int method)); +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng-manual.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +PNG_EXPORT(74, void, png_init_io, (png_structp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +PNG_EXPORT(75, void, png_set_error_fn, + (png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +PNG_EXPORT(77, void, png_set_write_fn, (png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +PNG_EXPORT(78, void, png_set_read_fn, (png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_structp png_ptr)); + +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +PNG_EXPORT(82, void, png_set_mem_fn, (png_structp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structp png_ptr)); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structp png_ptr, + png_user_transform_ptr read_user_transform_fn)); +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structp png_ptr, + png_user_transform_ptr write_user_transform_fn)); +#endif + +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structp png_ptr, + png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, + (png_const_structp png_ptr)); +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +/* Return information about the row currently being processed. Note that these + * APIs do not fail but will return unexpected results if called outside a user + * transform callback. Also note that when transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structp)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structp png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structp png_ptr, + png_voidp progressive_ptr, png_progressive_info_ptr info_fn, + png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, (png_const_structp png_ptr)); + +/* Function to be called when data becomes available */ +PNG_EXPORT(92, void, png_process_data, + (png_structp png_ptr, png_infop info_ptr, + png_bytep buffer, png_size_t buffer_size)); + +/* A function which may be called *only* within png_process_data to stop the + * processing of any more data. The function returns the number of bytes + * remaining, excluding any that libpng has cached internally. A subsequent + * call to png_process_data must supply these bytes again. If the argument + * 'save' is set to true the routine will first save all the pending data and + * will always return 0. + */ +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structp, int save)); + +/* A function which may be called *only* outside (after) a call to + * png_process_data. It returns the number of bytes of data to skip in the + * input. Normally it will return 0, but if it returns a non-zero value the + * application must skip than number of bytes of input data and pass the + * following data to the next call to png_process_data. + */ +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structp)); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Function that combines rows. 'new_row' is a flag that should come from + * the callback and be non-NULL if anything needs to be done; the library + * stores its own version of the new data internally and ignores the passed + * in value. + */ +PNG_EXPORT(93, void, png_progressive_combine_row, (png_structp png_ptr, + png_bytep old_row, png_const_bytep new_row)); +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +PNG_EXPORTA(94, png_voidp, png_malloc, + (png_structp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED); +/* Added at libpng version 1.4.0 */ +PNG_EXPORTA(95, png_voidp, png_calloc, + (png_structp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED); + +/* Added at libpng version 1.2.4 */ +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_structp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Frees a pointer allocated by png_malloc() */ +PNG_EXPORT(97, void, png_free, (png_structp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +PNG_EXPORT(98, void, png_free_data, + (png_structp png_ptr, png_infop info_ptr, png_uint_32 free_me, int num)); + +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application */ +PNG_EXPORT(99, void, png_data_freer, + (png_structp png_ptr, png_infop info_ptr, int freer, png_uint_32 mask)); + +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_structp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); +PNG_EXPORT(101, void, png_free_default, (png_structp png_ptr, png_voidp ptr)); +#endif + +#ifdef PNG_ERROR_TEXT_SUPPORTED +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(102, void, png_error, + (png_structp png_ptr, png_const_charp error_message), + PNG_NORETURN); + +/* The same, but the chunk name is prepended to the error string. */ +PNG_EXPORTA(103, void, png_chunk_error, (png_structp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +#else +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(104, void, png_err, (png_structp png_ptr), PNG_NORETURN); +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +PNG_EXPORT(105, void, png_warning, (png_structp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +PNG_EXPORT(106, void, png_chunk_warning, (png_structp png_ptr, + png_const_charp warning_message)); +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Benign error in libpng. Can continue, but may have a problem. + * User can choose whether to handle as a fatal error or as a warning. */ +# undef png_benign_error +PNG_EXPORT(107, void, png_benign_error, (png_structp png_ptr, + png_const_charp warning_message)); + +/* Same, chunk name is prepended to message. */ +# undef png_chunk_benign_error +PNG_EXPORT(108, void, png_chunk_benign_error, (png_structp png_ptr, + png_const_charp warning_message)); + +PNG_EXPORT(109, void, png_set_benign_errors, + (png_structp png_ptr, int allowed)); +#else +# ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +# else +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +PNG_EXPORT(110, png_uint_32, png_get_valid, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +PNG_EXPORT(112, png_bytepp, png_get_rows, + (png_const_structp png_ptr, png_const_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +PNG_EXPORT(113, void, png_set_rows, (png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +PNG_EXPORT(114, png_byte, png_get_channels, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +/* Returns image height in pixels. */ +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +/* Returns image bit_depth. */ +PNG_EXPORT(117, png_byte, png_get_bit_depth, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +/* Returns image color_type. */ +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +/* Returns image filter_type. */ +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +/* Returns image interlace_type. */ +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +/* Returns image compression_type. */ +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structp png_ptr, + png_const_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, + (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, + (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, + (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, + (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, + (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, + (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +PNG_EXPORT(130, png_const_bytep, png_get_signature, + (png_const_structp png_ptr, png_infop info_ptr)); + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(131, png_uint_32, png_get_bKGD, + (png_const_structp png_ptr, png_infop info_ptr, + png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(132, void, png_set_bKGD, (png_structp png_ptr, png_infop info_ptr, + png_const_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structp png_ptr, + png_const_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_structp png_ptr, + png_const_infop info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)); +#ifdef PNG_FIXED_POINT_SUPPORTED /* Otherwise not implemented */ +PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, + (png_const_structp png_ptr, + png_const_infop info_ptr, png_fixed_point *int_white_x, + png_fixed_point *int_white_y, png_fixed_point *int_red_x, + png_fixed_point *int_red_y, png_fixed_point *int_green_x, + png_fixed_point *int_green_y, png_fixed_point *int_blue_x, + png_fixed_point *int_blue_y)); +#endif +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_structp png_ptr, png_const_infop info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(135, void, png_set_cHRM, + (png_structp png_ptr, png_infop info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y)); +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_structp png_ptr, + png_infop info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)); +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, + png_fixed_point int_white_y, png_fixed_point int_red_x, + png_fixed_point int_red_y, png_fixed_point int_green_x, + png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)); +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, + (png_const_structp png_ptr, png_const_infop info_ptr, + double *file_gamma)); +PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_fixed_point *int_file_gamma)); +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(141, png_uint_32, png_get_hIST, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_uint_16p *hist)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(142, void, png_set_hIST, (png_structp png_ptr, + png_infop info_ptr, png_const_uint_16p hist)); +#endif + +PNG_EXPORT(143, png_uint_32, png_get_IHDR, + (png_structp png_ptr, png_infop info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, + int *interlace_method, int *compression_method, int *filter_method)); + +PNG_EXPORT(144, void, png_set_IHDR, + (png_structp png_ptr, png_infop info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int interlace_method, int compression_method, int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(145, png_uint_32, png_get_oFFs, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(146, void, png_set_oFFs, + (png_structp png_ptr, png_infop info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(147, png_uint_32, png_get_pCAL, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, + int *nparams, + png_charp *units, png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(148, void, png_set_pCAL, (png_structp png_ptr, + png_infop info_ptr, + png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, + int nparams, png_const_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(149, png_uint_32, png_get_pHYs, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(150, void, png_set_pHYs, + (png_structp png_ptr, png_infop info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +PNG_EXPORT(151, png_uint_32, png_get_PLTE, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_colorp *palette, int *num_palette)); + +PNG_EXPORT(152, void, png_set_PLTE, + (png_structp png_ptr, png_infop info_ptr, + png_const_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(153, png_uint_32, png_get_sBIT, + (png_const_structp png_ptr, png_infop info_ptr, + png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(154, void, png_set_sBIT, + (png_structp png_ptr, png_infop info_ptr, png_const_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structp png_ptr, + png_const_infop info_ptr, int *file_srgb_intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(156, void, png_set_sRGB, + (png_structp png_ptr, png_infop info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_structp png_ptr, + png_infop info_ptr, int srgb_intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(158, png_uint_32, png_get_iCCP, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_charpp name, int *compression_type, png_bytepp profile, + png_uint_32 *proflen)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(159, void, png_set_iCCP, + (png_structp png_ptr, png_infop info_ptr, + png_const_charp name, int compression_type, png_const_bytep profile, + png_uint_32 proflen)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(160, png_uint_32, png_get_sPLT, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(161, void, png_set_sPLT, + (png_structp png_ptr, png_infop info_ptr, + png_const_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +PNG_EXPORT(162, png_uint_32, png_get_text, + (png_const_structp png_ptr, png_const_infop info_ptr, + png_textp *text_ptr, int *num_text)); +#endif + +/* Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +PNG_EXPORT(163, void, png_set_text, + (png_structp png_ptr, png_infop info_ptr, + png_const_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(164, png_uint_32, png_get_tIME, + (png_const_structp png_ptr, png_infop info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(165, void, png_set_tIME, + (png_structp png_ptr, png_infop info_ptr, png_const_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(166, png_uint_32, png_get_tRNS, + (png_const_structp png_ptr, png_infop info_ptr, + png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(167, void, png_set_tRNS, + (png_structp png_ptr, png_infop info_ptr, + png_const_bytep trans_alpha, int num_trans, + png_const_color_16p trans_color)); +#endif + +#ifdef PNG_sCAL_SUPPORTED +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, + (png_const_structp png_ptr, png_const_infop info_ptr, + int *unit, double *width, double *height)); +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED +/* NOTE: this API is currently implemented using floating point arithmetic, + * consequently it can only be used on systems with floating point support. + * In any case the range of values supported by png_fixed_point is small and it + * is highly recommended that png_get_sCAL_s be used instead. + */ +PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, + (png_structp png_ptr, png_const_infop info_ptr, int *unit, + png_fixed_point *width, + png_fixed_point *height)); +#endif +PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, + (png_const_structp png_ptr, png_const_infop info_ptr, + int *unit, png_charpp swidth, png_charpp sheight)); + +PNG_FP_EXPORT(170, void, png_set_sCAL, + (png_structp png_ptr, png_infop info_ptr, + int unit, double width, double height)); +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_structp png_ptr, + png_infop info_ptr, int unit, png_fixed_point width, + png_fixed_point height)); +PNG_EXPORT(171, void, png_set_sCAL_s, + (png_structp png_ptr, png_infop info_ptr, + int unit, png_const_charp swidth, png_const_charp sheight)); +#endif /* PNG_sCAL_SUPPORTED */ + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +/* Provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. Because this turns off the default handling for chunks + that would otherwise be recognized the behavior of libpng transformations may + well become incorrect! + keep = 0: PNG_HANDLE_CHUNK_AS_DEFAULT: follow default behavior + = 1: PNG_HANDLE_CHUNK_NEVER: do not keep + = 2: PNG_HANDLE_CHUNK_IF_SAFE: keep only if safe-to-copy + = 3: PNG_HANDLE_CHUNK_ALWAYS: keep even if unsafe-to-copy +*/ +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, + (png_structp png_ptr, int keep, + png_const_bytep chunk_list, int num_chunks)); + +/* The handling code is returned; the result is therefore true (non-zero) if + * special handling is required, false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_structp png_ptr, + png_const_bytep chunk_name)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_structp png_ptr, + png_infop info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); +PNG_EXPORT(175, void, png_set_unknown_chunk_location, + (png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structp png_ptr, + png_const_infop info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +PNG_EXPORT(177, void, png_set_invalid, + (png_structp png_ptr, png_infop info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +PNG_EXPORT(178, void, png_read_png, (png_structp png_ptr, png_infop info_ptr, + int transforms, png_voidp params)); +PNG_EXPORT(179, void, png_write_png, (png_structp png_ptr, png_infop info_ptr, + int transforms, png_voidp params)); +#endif + +PNG_EXPORT(180, png_const_charp, png_get_copyright, + (png_const_structp png_ptr)); +PNG_EXPORT(181, png_const_charp, png_get_header_ver, + (png_const_structp png_ptr)); +PNG_EXPORT(182, png_const_charp, png_get_header_version, + (png_const_structp png_ptr)); +PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, + (png_const_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structp png_ptr, + png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +PNG_EXPORT(185, void, png_set_strip_error_numbers, + (png_structp png_ptr, + png_uint_32 strip_mode)); +#endif + +/* Added in libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +PNG_EXPORT(186, void, png_set_user_limits, (png_structp png_ptr, + png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(187, png_uint_32, png_get_user_width_max, + (png_const_structp png_ptr)); +PNG_EXPORT(188, png_uint_32, png_get_user_height_max, + (png_const_structp png_ptr)); +/* Added in libpng-1.4.0 */ +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structp png_ptr, + png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, + (png_const_structp png_ptr)); +/* Added in libpng-1.4.1 */ +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structp png_ptr, + png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, + (png_const_structp png_ptr)); +#endif + +#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) +PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, + (png_const_structp png_ptr, png_const_infop info_ptr)); + +PNG_FP_EXPORT(196, float, png_get_x_offset_inches, + (png_const_structp png_ptr, png_const_infop info_ptr)); +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, + (png_structp png_ptr, png_const_infop info_ptr)); +#endif + +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structp png_ptr, + png_const_infop info_ptr)); +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, + (png_structp png_ptr, png_const_infop info_ptr)); +#endif + +# ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structp png_ptr, + png_const_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ + +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_structp png_ptr)); + +PNG_EXPORTA(200, png_const_bytep, png_get_io_chunk_name, + (png_structp png_ptr), PNG_DEPRECATED); +PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, + (png_const_structp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +# define PNG_IO_READING 0x0001 /* currently reading */ +# define PNG_IO_WRITING 0x0002 /* currently writing */ +# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ + +/* Interlace support. The following macros are always defined so that if + * libpng interlace handling is turned off the macros may be used to handle + * interlaced images within the application. + */ +#define PNG_INTERLACE_ADAM7_PASSES 7 + +/* Two macros to return the first row and first column of the original, + * full, image which appears in a given pass. 'pass' is in the range 0 + * to 6 and the result is in the range 0 to 7. + */ +#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) + +/* A macro to return the offset between pixels in the output row for a pair of + * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that + * follows. Note that ROW_OFFSET is the offset from one row to the next whereas + * COL_OFFSET is from one column to the next, within a row. + */ +#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) +#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) + +/* Two macros to help evaluate the number of rows or columns in each + * pass. This is expressed as a shift - effectively log2 of the number or + * rows or columns in each 8x8 tile of the original image. + */ +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) + +/* Hence two macros to determine the number of rows or columns in a given + * pass of an image given its height or width. In fact these macros may + * return non-zero even though the sub-image is empty, because the other + * dimension may be empty for a small image. + */ +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) + +/* For the reader row callbacks (both progressive and sequential) it is + * necessary to find the row in the output image given a row in an interlaced + * image, so two more macros: + */ +#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ + (((yIn)<>(((7-(off))-(pass))<<2)) & 0xF) | \ + ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) + +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535) +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); +#endif + +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_structp png_ptr, + png_const_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); +#endif +#ifdef PNG_SAVE_INT_32_SUPPORTED +PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ +#endif + +#ifdef PNG_USE_READ_MACROS +/* Inline macros to do direct reads of bytes from the input buffer. + * The png_get_int_32() routine assumes we are using two's complement + * format for negative values, which is almost certainly true. + */ +# define png_get_uint_32(buf) \ + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) + + /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the + * function) incorrectly returned a value of type png_uint_32. + */ +# define png_get_uint_16(buf) \ + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) + +# define png_get_int_32(buf) \ + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ + : (png_int_32)png_get_uint_32(buf))) +#endif + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project + * defs + */ + +/* The last ordinal number (this is the *last* one already used; the next + * one to use is one more than this.) Maintainer, remember to add an entry to + * scripts/symbols.def as well. + */ +#ifdef PNG_EXPORT_LAST_ORDINAL + PNG_EXPORT_LAST_ORDINAL(233); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/include/nana/extrlib/pngconf.h b/include/nana/extrlib/pngconf.h new file mode 100644 index 00000000..6c1db14e --- /dev/null +++ b/include/nana/extrlib/pngconf.h @@ -0,0 +1,596 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.5.8 - February 1, 2012 + * + * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* PNG_NO_LIMITS_H may be used to turn off the use of the standard C + * definition file for machine specific limits, this may impact the + * correctness of the definitons below (see uses of INT_MAX). + */ +# ifndef PNG_NO_LIMITS_H +# include +# endif + +/* For the memory copy APIs (i.e. the standard definitions of these), + * because this file defines png_memcpy and so on the base APIs must + * be defined here. + */ +# ifdef BSD +# include +# else +# include +# endif + +/* For png_FILE_p - this provides the standard definition of a + * FILE + */ +# ifdef PNG_STDIO_SUPPORTED +# include +# endif +#endif + +/* This controls optimization of the reading of 16 and 32 bit values + * from PNG files. It can be set on a per-app-file basis - it + * just changes whether a macro is used to the function is called. + * The library builder sets the default, if read functions are not + * built into the library the macro implementation is forced on. + */ +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED +# define PNG_USE_READ_MACROS +#endif +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif +#endif + +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. + */ + +/* The PNGARG macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +# ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +# else + +# ifdef _NO_PROTO +# define PNGARG(arglist) () +# else +# define PNGARG(arglist) arglist +# endif /* _NO_PROTO */ + +# endif /* OF */ + +#endif /* PNGARG */ + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows sytems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. + */ + +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. + */ + +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows/x86 systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. + */ +#if ( defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) ) &&\ + ( defined(_X86_) || defined(_X64_) || defined(_M_IX86) ||\ + defined(_M_X64) || defined(_M_IA64) ) + /* Windows system (DOS doesn't support DLLs) running on x86/x64. Includes + * builds under Cygwin or MinGW. Also includes Watcom builds but these need + * special treatment because they are not compatible with GCC or Visual C + * because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif + +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 +# define PNGAPI __stdcall +# endif +# else + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) + ERROR: PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed +# endif + +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ + +#else /* !Windows/x86 */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. + */ +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT +# endif + +# ifndef PNG_IMPEXP +# define PNG_IMPEXP +# endif +#endif + +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args +#endif + +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ +#ifndef PNG_EXPORTA + +# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ + PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ + extern attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args)\ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +#endif + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. + */ +# if defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# endif /* __GNUC__ */ + +# if defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) +# endif +# ifndef PNG_PRIVATE +# define PNG_PRIVATE __declspec(deprecated) +# endif +# endif /* _MSC_VER */ +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args) +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args) +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST here. + * + * This should not change how the APIs are called, so it can be done + * on a per-file basis in the application. + */ +#ifndef PNG_CONST +# ifndef PNG_NO_CONST +# define PNG_CONST const +# else +# define PNG_CONST +# endif +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. + */ + +#if defined(INT_MAX) && (INT_MAX > 0x7ffffffeL) +typedef unsigned int png_uint_32; +typedef int png_int_32; +#else +typedef unsigned long png_uint_32; +typedef long png_int_32; +#endif +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +#ifdef PNG_NO_SIZE_T +typedef unsigned int png_size_t; +#else +typedef size_t png_size_t; +#endif +#define png_sizeof(x) (sizeof (x)) + +/* The following is needed for medium model support. It cannot be in the + * pngpriv.h header. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + * defines FAR. (SJT) + */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K /* only used in build */ +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#ifdef FAR +# ifdef M_I86MM +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + * to fixed-point with a multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef PNG_CONST void FAR * png_const_voidp; +typedef png_byte FAR * png_bytep; +typedef PNG_CONST png_byte FAR * png_const_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef PNG_CONST png_uint_32 FAR * png_const_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef PNG_CONST png_int_32 FAR * png_const_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef PNG_CONST png_uint_16 FAR * png_const_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST png_int_16 FAR * png_const_int_16p; +typedef char FAR * png_charp; +typedef PNG_CONST char FAR * png_const_charp; +typedef png_fixed_point FAR * png_fixed_point_p; +typedef PNG_CONST png_fixed_point FAR * png_const_fixed_point_p; +typedef png_size_t FAR * png_size_tp; +typedef PNG_CONST png_size_t FAR * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +typedef PNG_CONST double FAR * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, + * and no smaller than png_uint_32. Casts from png_size_t or png_uint_32 + * to png_alloc_size_t are not necessary; in fact, it is recommended + * not to use them at all so that the compiler can complain when something + * turns out to be problematic. + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect + * to encounter practical situations that require such conversions. + */ +#if defined(__TURBOC__) && !defined(__FLAT__) + typedef unsigned long png_alloc_size_t; +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + typedef unsigned long png_alloc_size_t; +# else + /* This is an attempt to detect an old Windows system where (int) is + * actually 16 bits, in that case png_malloc must have an argument with a + * bigger size to accomodate the requirements of the library. + */ +# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) && \ + (!defined(INT_MAX) || INT_MAX <= 0x7ffffffeL) + typedef DWORD png_alloc_size_t; +# else + typedef png_size_t png_alloc_size_t; +# endif +# endif +#endif + +#endif /* PNGCONF_H */ diff --git a/include/nana/extrlib/pnglibconf.h b/include/nana/extrlib/pnglibconf.h new file mode 100644 index 00000000..3ca1c16f --- /dev/null +++ b/include/nana/extrlib/pnglibconf.h @@ -0,0 +1,189 @@ + +/* libpng STANDARD API DEFINITION */ + +/* pnglibconf.h - library build configuration */ + +/* Libpng 1.5.8 - February 1, 2012 */ + +/* Copyright (c) 1998-2011 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Derived from: scripts/pnglibconf.dfa */ +/* If you edit this file by hand you must obey the rules expressed in */ +/* pnglibconf.dfa with respect to the dependencies between the following */ +/* symbols. It is much better to generate a new file using */ +/* scripts/libpngconf.mak */ + +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* settings */ +#define PNG_API_RULE 0 +#define PNG_CALLOC_SUPPORTED +#define PNG_COST_SHIFT 3 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_sCAL_PRECISION 5 +#define PNG_USER_CHUNK_CACHE_MAX 0 +#define PNG_USER_CHUNK_MALLOC_MAX 0 +#define PNG_USER_HEIGHT_MAX 1000000 +#define PNG_USER_WIDTH_MAX 1000000 +#define PNG_WEIGHT_SHIFT 8 +#define PNG_ZBUF_SIZE 8192 +/* end of settings */ +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGN_MEMORY_SUPPORTED +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_cHRM_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +#endif /* PNGLCONF_H */ diff --git a/include/nana/extrlib/zlib.h b/include/nana/extrlib/zlib.h new file mode 100644 index 00000000..79142d11 --- /dev/null +++ b/include/nana/extrlib/zlib.h @@ -0,0 +1,1732 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.6, January 29th, 2012 + + Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.6" +#define ZLIB_VERNUM 0x1260 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 6 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is not required to perform an + inflation in one step. However it may be used to inform inflate that a + faster approach can be used for the single inflate() call. Z_FINISH also + informs inflate to not maintain a sliding window if the stream completes, + which reduces inflate's memory footprint. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); +#define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc_(g)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#ifndef Z_SOLO + ZEXTERN unsigned long ZEXPORT gzflags OF((void)); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/include/nana/filesystem/file_iterator.hpp b/include/nana/filesystem/file_iterator.hpp new file mode 100644 index 00000000..a4801571 --- /dev/null +++ b/include/nana/filesystem/file_iterator.hpp @@ -0,0 +1,255 @@ +/* + * A File Iterator Implementation + * Copyright(C) 2003 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: stdex/filesystem/file_iterator.hpp + * @description: + * file_iterator is a toolkit for applying each file and directory in a + * specified path. + */ + +#ifndef NANA_FILESYSTEM_FILE_ITERATOR_HPP +#define NANA_FILESYSTEM_FILE_ITERATOR_HPP +#include +#include + +#include + +#ifdef NANA_WINDOWS + #include + typedef HANDLE find_handle_t; +#elif defined(NANA_LINUX) + #include + #include + #include + typedef DIR* find_handle_t; +#endif + +namespace nana +{ +namespace filesystem +{ + struct fileinfo + { + fileinfo(); +#ifdef NANA_WINDOWS + fileinfo(const WIN32_FIND_DATA& wfd); +#elif NANA_LINUX + fileinfo(const nana::string& filename, const struct stat &); +#endif + nana::string name; + + unsigned long size; + bool directory; + }; + + template + class basic_file_iterator + :public std::iterator + { + public: + typedef FileInfo value_type; + + basic_file_iterator():end_(true), handle_(nullptr){} + + basic_file_iterator(const nana::string& file_path) + :end_(false), handle_(nullptr) + { + _m_prepare(file_path); + } + + const value_type& + operator*() const { return value_; } + + const value_type* + operator->() const { return &(operator*()); } + + basic_file_iterator& operator++() + { _m_read(); return *this; } + + basic_file_iterator operator++(int) + { + basic_file_iterator tmp = *this; + _m_read(); + return tmp; + } + + bool equal(const basic_file_iterator& x) const + { + if(end_ && (end_ == x.end_)) return true; + return (value_.name == x.value_.name); + } + private: + template + static bool _m_ignore(const Char * p) + { + while(*p == '.') + ++p; + return (*p == 0); + } + + void _m_prepare(const nana::string& file_path) + { + #if defined(NANA_WINDOWS) + path_ = file_path; + auto pat = file_path; + DWORD attr = ::GetFileAttributes(pat.data()); + if((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)) + pat += STR("\\*"); + + ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd_); + + if(handle == INVALID_HANDLE_VALUE) + { + end_ = true; + return; + } + + while(_m_ignore(wfd_.cFileName)) + { + if(::FindNextFile(handle, &wfd_) == 0) + { + end_ = true; + ::FindClose(handle); + return; + } + } + value_ = value_type(wfd_); + #elif defined(NANA_LINUX) + path_ = nana::charset(file_path); + if(path_.size() && (path_[path_.size() - 1] != '/')) + path_ += '/'; + find_handle_t handle = opendir(path_.c_str()); + end_ = true; + if(handle) + { + struct dirent * dnt = readdir(handle); + if(dnt) + { + while(_m_ignore(dnt->d_name)) + { + dnt = readdir(handle); + if(dnt == 0) + { + closedir(handle); + return; + } + } + + struct stat fst; + if(stat((path_ + dnt->d_name).c_str(), &fst) == 0) + { + value_ = value_type(nana::charset(dnt->d_name), fst); + } + else + { + value_.name = nana::charset(dnt->d_name); + value_.size = 0; + value_.directory = false; + } + end_ = false; + } + } + #endif + if(false == end_) + { + find_ptr_ = std::shared_ptr(new find_handle_t(handle), inner_handle_deleter()); + handle_ = handle; + } + } + + void _m_read() + { + if(handle_) + { + #if defined(NANA_WINDOWS) + if(::FindNextFile(handle_, &wfd_) != 0) + { + while(_m_ignore(wfd_.cFileName)) + { + if(::FindNextFile(handle_, &wfd_) == 0) + { + end_ = true; + return; + } + } + value_ = value_type(wfd_); + } + else + end_ = true; + #elif defined(NANA_LINUX) + struct dirent * dnt = readdir(handle_); + if(dnt) + { + while(_m_ignore(dnt->d_name)) + { + dnt = readdir(handle_); + if(dnt == 0) + { + end_ = true; + return; + } + } + struct stat fst; + if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0) + value_ = value_type(nana::charset(dnt->d_name), fst); + else + value_.name = nana::charset(dnt->d_name); + } + else + end_ = true; + #endif + } + } + private: + struct inner_handle_deleter + { + void operator()(find_handle_t * handle) + { + if(handle && *handle) + { + #if defined(NANA_WINDOWS) + ::FindClose(*handle); + #elif defined(NANA_LINUX) + ::closedir(*handle); + #endif + } + delete handle; + } + }; + private: + bool end_; + +#if defined(NANA_WINDOWS) + WIN32_FIND_DATA wfd_; + nana::string path_; +#elif defined(NANA_LINUX) + std::string path_; +#endif + std::shared_ptr find_ptr_; + + find_handle_t handle_; + value_type value_; + }; + + template + inline bool operator==(const basic_file_iterator & x, const basic_file_iterator & y) + { + return x.equal(y); + } + + template + inline bool operator!=(const basic_file_iterator & x, const basic_file_iterator & y) + { + return !x.equal(y); + } + + typedef basic_file_iterator file_iterator; +}//end namespace filesystem +}//end namespace nana + +#endif diff --git a/include/nana/filesystem/fs_utility.hpp b/include/nana/filesystem/fs_utility.hpp new file mode 100644 index 00000000..d52e54dd --- /dev/null +++ b/include/nana/filesystem/fs_utility.hpp @@ -0,0 +1,65 @@ + +#ifndef NANA_FILESYSTEM_FS_UTILITY_HPP +#define NANA_FILESYSTEM_FS_UTILITY_HPP + +#include +#include + +namespace nana +{ +namespace filesystem +{ + struct error + { + enum + { + none = 0 + }; + }; + + struct attribute + { + long long bytes; + bool is_directory; + tm modified; + }; + + bool file_attrib(const nana::string& file, attribute&); + long long filesize(const nana::string& file); + + bool mkdir(const nana::string& dir, bool & if_exist); + bool modified_file_time(const nana::string& file, struct tm&); + + nana::string path_user(); + nana::string path_current(); + + bool rmfile(const nana::char_t* file); + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); + nana::string root(const nana::string& path); + + class path + { + public: + struct type + { enum{not_exist, file, directory}; + }; + + path(); + path(const nana::string&); + + bool empty() const; + path root() const; + int what() const; + + nana::string name() const; + private: +#if defined(NANA_WINDOWS) + nana::string text_; +#else + std::string text_; +#endif + }; +}//end namespace filesystem +}//end namespace nana + +#endif diff --git a/include/nana/fwd.hpp b/include/nana/fwd.hpp new file mode 100644 index 00000000..62d824cb --- /dev/null +++ b/include/nana/fwd.hpp @@ -0,0 +1,22 @@ +/* + * Forward Declarations + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/fwd.hpp + * + */ + +#ifndef NANA_FWD_HPP +#define NANA_FWD_HPP + +namespace nana +{ + class filebox; + class msgbox; +}//end namespace nana +#endif //NANA_FWD_HPP diff --git a/include/nana/gui.hpp b/include/nana/gui.hpp new file mode 100644 index 00000000..70bcb077 --- /dev/null +++ b/include/nana/gui.hpp @@ -0,0 +1 @@ +#include "gui/wvl.hpp" \ No newline at end of file diff --git a/include/nana/gui/animation.hpp b/include/nana/gui/animation.hpp new file mode 100644 index 00000000..a1f15a63 --- /dev/null +++ b/include/nana/gui/animation.hpp @@ -0,0 +1,82 @@ +/* + * An Animation Implementation + * Copyright(C) 2003-2013 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/gui/animation.hpp + */ + +#ifndef NANA_GUI_ANIMATION_HPP +#define NANA_GUI_ANIMATION_HPP + +#include + +#include +#include + + +namespace nana +{ + class animation; + /// Holds the frames and frame builders. Have reference semantics for efficiency. + class frameset + { + friend class animation; + public: + /// function which builds frames. + typedef std::function framebuilder; + + struct impl; + public: + frameset(); + void push_back(const paint::image&); ///< Inserts frames at the end. + void push_back(paint::image&&); + void push_back(framebuilder& fb, std::size_t length); ///< Insters a framebuilder and the number of frames that it generates. + void push_back(framebuilder&& fb, std::size_t length); ///< Insters a framebuilder and the number of frames that it generates. + private: + std::shared_ptr impl_; + }; + /// Easy way to display an animation or create an animated GUI + class animation + { + struct branch_t + { + frameset frames; + std::function condition; + }; + + struct impl; + class performance_manager; + public: + animation(); + + void push_back(const frameset& frms); + /* + void branch(const std::string& name, const frameset& frms) + { + impl_->branches[name].frames = frms; + } + + void branch(const std::string& name, const frameset& frms, std::function condition) + { + auto & br = impl_->branches[name]; + br.frames = frms; + br.condition = condition; + } + */ + + void looped(bool enable); ///< Enables or disables the animation repeating playback. + + void play(); + + void pause(); + + void output(window wd, const nana::point& pos); + private: + impl * impl_; + }; +} //end namespace nana +#endif //NANA_GUI_ANIMATION_HPP diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp new file mode 100644 index 00000000..aade6c38 --- /dev/null +++ b/include/nana/gui/basis.hpp @@ -0,0 +1,241 @@ +/* + * Basis Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/basis.hpp + * + * This file provides basis class and data structrue that required by gui + */ + +#ifndef NANA_GUI_BASIS_HPP +#define NANA_GUI_BASIS_HPP + +#include "../basic_types.hpp" +#include "../traits.hpp" //metacomp::fixed_type_set + +namespace nana +{ + namespace detail + { + struct native_window_handle_impl{}; + struct window_handle_impl{}; + struct event_handle_impl{}; + } + + enum class checkstate + { + unchecked, checked, partial + }; + + enum class window_border + { + none, + left, right, top, bottom, + top_left, top_right, bottom_left, bottom_right + }; + + enum class bground_mode + { + none, + basic, + blend + }; + + namespace category + { + enum class flags + { + super, + widget = 0x1, + lite_widget = 0x3, + root = 0x5, + frame = 0x9 + }; + //wait for constexpr + struct widget_tag{ static const flags value = flags::widget; }; + struct lite_widget_tag : widget_tag{ static const flags value = flags::lite_widget;}; + struct root_tag : widget_tag{ static const flags value = flags::root; }; + struct frame_tag: widget_tag{ static const flags value = flags::frame; }; + }// end namespace category + + typedef detail::native_window_handle_impl * native_window_type; + + typedef detail::window_handle_impl* window; ///< \see [What is window class ](https://sourceforge.net/p/nanapro/discussion/general/thread/bd0fabfb/) + typedef detail::event_handle_impl* event_handle; + + + struct keyboard + { + enum t{ + //Control Code for ASCII + select_all = 0x1, + end_of_text = 0x3, //Ctrl+C + backspace = 0x8, tab = 0x9, + enter_n = 0xA, enter = 0xD, enter_r = 0xD, + alt = 0x12, + sync_idel = 0x16, //Ctrl+V + cancel = 0x18, //Ctrl+X + end_of_medium = 0x19, //Ctrl+Y + substitute = 0x1A, //Ctrl+Z + escape = 0x1B, + + //The following names are intuitive name of ASCII control codes + copy = 0x3, //end_of_text + paste = 0x16, //sync_idel + cut = 0x18, //cancel + redo = 0x19, //end_of_medium + undo = 0x1A, //substitue + + //System Code for OS + os_pageup = 0x21, os_pagedown, + os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, + os_insert = 0x2D, os_del + }; + }; + + namespace color + { + enum + { + white = 0xFFFFFF, + blue = 0x0000FF, + green = 0x00FF00, + red = 0xFF0000, + + button_face_shadow_start = 0xF5F4F2, + button_face_shadow_end = 0xD5D2CA, + button_face = 0xD4D0C8, + dark_border = 0x404040, + gray_border = 0x808080, + highlight = 0x1CC4F7 + }; + }; + + enum class cursor + { + hand = 60, ///< displays a hand to indicate a text or an element is clickable + arrow = 68, ///< the default shape + wait = 150, ///< indicates the system is currently busy + iterm = 152, ///< A text caret. Displays a caret to indicate the UI is input able + size_we = 108, + size_ns = 116, + size_top_left = 134, + size_top_right = 136, + size_bottom_left = 12, + size_bottom_right = 14 + }; + + enum class mouse + { + any_button, + left_button, + middle_button, + right_button + }; + + enum class z_order_action + { + none, + bottom, ///< brings a window at the bottom of z-order. + top, ///< brings a widget at the top of the z-order. + topmost, ///< brings a window at the top of the z-order and stays here. + foreground ///< brings a window to the foreground. + }; + + /// Window appearance structure defined to specify the appearance of a form + struct appearance + { + bool taskbar; + bool floating; + bool no_activate; + + bool minimize; + bool maximize; + bool sizable; + + bool decoration; + + appearance(); + appearance(bool has_decoration, bool taskbar, bool floating, bool no_activate, bool min, bool max, bool sizable); + }; + /// Provided to generate an appearance object with better readability and understandability + struct appear + { + struct minimize{}; + struct maximize{}; + struct sizable{}; + struct taskbar{}; + struct floating{}; + struct no_activate{}; + /// Create an appearance of a window with "decoration" + template< typename Minimize = null_type, + typename Maximize = null_type, + typename Sizable = null_type, + typename Floating = null_type, + typename NoActive = null_type> + struct decorate + { + typedef meta::fixed_type_set set_type; + + operator appearance() const + { + return appearance( true, true, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value + ); + } + }; + /// Create an appearance of a window without "decoration" + template < typename Taskbar = null_type, + typename Floating = null_type, + typename NoActive = null_type, + typename Minimize = null_type, + typename Maximize = null_type, + typename Sizable = null_type> + struct bald + { + typedef meta::fixed_type_set set_type; + + operator appearance() const + { + return appearance( false, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value + ); + } + }; + /// Create a window with decoration depending on the first non-type template parameter + template < bool HasDecoration = true, + typename Sizable = null_type, + typename Taskbar = null_type, + typename Floating = null_type, + typename NoActive = null_type> + struct optional + { + typedef meta::fixed_type_set set_type; + + operator appearance() const + { + return appearance(HasDecoration, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + true, true, + set_type::template count::value); + } + }; + };//end namespace apper +}//end namespace nana +#endif diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp new file mode 100644 index 00000000..f84e3692 --- /dev/null +++ b/include/nana/gui/detail/basic_window.hpp @@ -0,0 +1,241 @@ +/* + * A Basic Window Widget Definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/basic_window.hpp + */ + +#ifndef NANA_GUI_DETAIL_BASIC_WINDOW_HPP +#define NANA_GUI_DETAIL_BASIC_WINDOW_HPP +#include "drawer.hpp" +#include "events_holder.hpp" +#include "../basis.hpp" +#include +#include +#include +#include + +namespace nana{ + class widget; //declaration ofr nana/widgets/widget.hpp +namespace detail +{ + struct basic_window; + + class caret_descriptor + { + public: + typedef basic_window core_window_t; + + caret_descriptor(core_window_t*, unsigned width, unsigned height); + ~caret_descriptor(); + void set_active(bool); + core_window_t* window() const; + void position(int x, int y); + void effective_range(::nana::rectangle); + ::nana::point position() const; + void visible(bool isshow); + bool visible() const; + ::nana::size size() const; + void size(const ::nana::size&); + + void update(); + private: + void _m_visible(bool isshow); + private: + core_window_t* wd_; + ::nana::point point_; + ::nana::size size_; + ::nana::size paint_size_; + bool visible_; + bool real_visible_state_; + bool out_of_range_; + ::nana::rectangle effective_range_; + };//end class caret_descriptor + + //tab_type + //@brief: Define some constant about tab category, these flags can be combine with operator | + struct tab_type + { + enum t + { + none, //process by nana + tabstop, //move to the next tabstop window + eating, //process by current window + }; + }; + + //struct basic_window + //@brief: a window data structure descriptor + struct basic_window + : public events_holder + { + typedef std::vector container; + + struct root_context + { + bool focus_changed; + }; + + enum class update_state + { + none, lazy, refresh + }; + + struct edge_nimbus_action + { + basic_window * window; + bool rendered; + }; + + //basic_window + //@brief: constructor for the root window + basic_window(basic_window* owner, widget*, category::root_tag**); + + template + basic_window(basic_window* parent, const rectangle& r, widget* wdg, Category**) + : widget_ptr(wdg), other(Category::value) + { + drawer.bind(this); + if(parent) + { + _m_init_pos_and_size(parent, r); + _m_initialize(parent); + } + } + + ~basic_window(); + + //bind_native_window + //@brief: bind a native window and baisc_window + void bind_native_window(native_window_type, unsigned width, unsigned height, unsigned extra_width, unsigned extra_height, paint::graphics&); + + void frame_window(native_window_type); + + bool is_ancestor_of(const basic_window* wd) const; + bool visible_parents() const; + bool belong_to_lazy() const; + public: + //Override event_holder + bool set_events(const std::shared_ptr&) override; + general_events * get_events() const override; + private: + void _m_init_pos_and_size(basic_window* parent, const rectangle&); + void _m_initialize(basic_window* parent); + public: +#if defined(NANA_LINUX) + point pos_native; +#endif + point pos_root; //coordinate for root window + point pos_owner; + size dimension; + ::nana::size min_track_size; + ::nana::size max_track_size; + + bool visible; + + unsigned extra_width; + unsigned extra_height; + + basic_window *parent; + basic_window *owner; + + ::nana::string title; + ::nana::detail::drawer drawer; //Self Drawer with owen graphics + basic_window* root_widget; //A pointer refers to the root basic window, if the window is a root, the pointer refers to itself. + paint::graphics* root_graph; //Refer to the root buffer graphics + cursor predef_cursor; + widget* const widget_ptr; + + struct flags_type + { + bool enabled :1; + bool dbl_click :1; + bool capture :1; //if mouse button is down, it always receive mouse move even the mouse is out of its rectangle + bool modal :1; + bool take_active:1; //If take_active is false, other.active_window still keeps the focus. + bool refreshing :1; + bool destroying :1; + bool dropable :1; //Whether the window has make mouse_drop event. + bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen. + bool borderless :1; + unsigned Reserved :22; + unsigned char tab; //indicate a window that can receive the keyboard TAB + mouse_action action; + }flags; + + struct + { + caret_descriptor* caret; + std::shared_ptr events_ptr; + general_events* attached_events; + }together; + + struct + { + color_t foreground; + color_t background; + color_t active; + }color; + + struct + { + effects::edge_nimbus edge_nimbus; + effects::bground_interface * bground; + double bground_fade_rate; + }effect; + + struct other_tag + { + struct attr_frame_tag + { + native_window_type container{nullptr}; + std::vector attach; + }; + + struct attr_root_tag + { + container frames; //initialization is null, it will be created while creating a frame widget. Refer to WindowManager::create_frame + container tabstop; + std::vector effects_edge_nimbus; + basic_window* focus{nullptr}; + basic_window* menubar{nullptr}; + root_context context; + bool ime_enabled{false}; +#if defined(NANA_WINDOWS) + cursor running_cursor{ nana::cursor::arrow }; +#endif + cursor state_cursor{nana::cursor::arrow}; + basic_window* state_cursor_window{ nullptr }; + }; + + const category::flags category; + basic_window *active_window; //if flags.take_active is false, the active_window still keeps the focus, + //if the active_window is null, the parent of this window keeps focus. + paint::graphics glass_buffer; //if effect.bground is avaiable. Refer to window_layout::make_bground. + update_state upd_state; + + union + { + attr_root_tag * root; + attr_frame_tag * frame; + }attribute; + + other_tag(category::flags); + ~other_tag(); + }other; + + native_window_type root; //root Window handle + unsigned thread_id; //the identifier of the thread that created the window. + unsigned index; + container children; + }; + +}//end namespace detail +}//end namespace nana +#endif + diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp new file mode 100644 index 00000000..d58cc680 --- /dev/null +++ b/include/nana/gui/detail/bedrock.hpp @@ -0,0 +1,102 @@ +/* + * A Bedrock Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/bedrock.hpp + */ + +#ifndef NANA_GUI_DETAIL_BEDROCK_HPP +#define NANA_GUI_DETAIL_BEDROCK_HPP +#include "window_manager.hpp" +#include "events_operation.hpp" +#include "runtime_manager.hpp" +#include "general_events.hpp" +#include "internal_scope_guard.hpp" + +namespace nana +{ +namespace detail +{ + struct native_interface; + + class element_store; + + //class bedrock + //@brief: bedrock is a fundamental core component, it provides a abstract to the OS platform + // and some basic functions. + class bedrock + { + bedrock(); + public: + typedef native_interface interface_type; + typedef window_manager window_manager_t; + typedef window_manager_t::core_window_t core_window_t; + + struct thread_context; + + ~bedrock(); + void pump_event(window, bool is_modal); + void map_thread_root_buffer(core_window_t* ); + static int inc_window(unsigned tid = 0); + thread_context* open_thread_context(unsigned tid = 0); + thread_context* get_thread_context(unsigned tid = 0); + void remove_thread_context(unsigned tid = 0); + static bedrock& instance(); + + ::nana::category::flags category(core_window_t*); + core_window_t* focus(); + native_window_type root(core_window_t*); + + void set_menubar_taken(core_window_t*); + core_window_t* get_menubar_taken(); + bool close_menu_if_focus_other_window(native_window_type focus); + void set_menu(native_window_type menu_window, bool is_keyboard_condition); + native_window_type get_menu(native_window_type owner, bool is_keyboard_condition); + native_window_type get_menu(); + void remove_menu(); + void empty_menu(); + + void get_key_state(arg_keyboard&); + bool set_keyboard_shortkey(bool yes); + bool whether_keyboard_shortkey() const; + + element_store& get_element_store() const; + public: + void event_expose(core_window_t *, bool exposed); + void event_move(core_window_t*, int x, int y); + bool event_msleave(core_window_t*); + void thread_context_destroy(core_window_t*); + void thread_context_lazy_refresh(); + void update_cursor(core_window_t*); + void set_cursor(core_window_t*, nana::cursor, thread_context*); + void define_state_cursor(core_window_t*, nana::cursor, thread_context*); + void undefine_state_cursor(core_window_t*, thread_context*); + public: + window_manager_t wd_manager; + events_operation evt_operation; + + runtime_manager rt_manager; + + bool emit(event_code, core_window_t*, const arg_mouse&, bool ask_update, thread_context*); + bool emit(event_code, core_window_t*, const event_arg_interface&, bool ask_update, thread_context*); + bool emit_drawer(event_code, core_window_t*, const event_arg_interface&, thread_context*); + private: + void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg_interface&); + void _m_event_filter(event_code, core_window_t*, thread_context*); + void _m_except_handler(); + private: + static bedrock bedrock_object; + + struct private_impl; + private_impl *impl_; + };//end class bedrock +}//end namespace detail +}//end namespace nana + +#endif + diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp new file mode 100644 index 00000000..8cb5465a --- /dev/null +++ b/include/nana/gui/detail/drawer.hpp @@ -0,0 +1,165 @@ +/* + * A Drawer Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/drawer.hpp + */ + +#ifndef NANA_GUI_DETAIL_DRAWER_HPP +#define NANA_GUI_DETAIL_DRAWER_HPP + +#include +#include "general_events.hpp" +#include +#include +#include + +namespace nana +{ + class widget; + + class drawer_trigger + : ::nana::noncopyable, ::nana::nonmovable + { + public: + typedef widget& widget_reference; + typedef paint::graphics& graph_reference; + + virtual ~drawer_trigger(); + virtual void attached(widget_reference, graph_reference); //none-const + virtual void detached(); //none-const + + virtual void typeface_changed(graph_reference); + virtual void refresh(graph_reference); + + virtual void resizing(graph_reference, const arg_resizing&); + virtual void resized(graph_reference, const arg_resized&); + virtual void move(graph_reference, const arg_move&); + virtual void click(graph_reference, const arg_mouse&); + virtual void dbl_click(graph_reference, const arg_mouse&); + virtual void mouse_enter(graph_reference, const arg_mouse&); + virtual void mouse_move(graph_reference, const arg_mouse&); + virtual void mouse_leave(graph_reference, const arg_mouse&); + virtual void mouse_down(graph_reference, const arg_mouse&); + virtual void mouse_up(graph_reference, const arg_mouse&); + virtual void mouse_wheel(graph_reference, const arg_wheel&); + virtual void mouse_dropfiles(graph_reference, const arg_dropfiles&); + + virtual void focus(graph_reference, const arg_focus&); + virtual void key_press(graph_reference, const arg_keyboard&); + virtual void key_char(graph_reference, const arg_keyboard&); + virtual void key_release(graph_reference, const arg_keyboard&); + virtual void shortkey(graph_reference, const arg_keyboard&); + + void _m_reset_overrided(); + bool _m_overrided() const; + private: + bool overrided_{false}; + }; + + namespace detail + { + struct basic_window; + + namespace dynamic_drawing + { + //declaration + class object; + } + + //@brief: Every window has a drawer, the drawer holds a drawer_trigger for + // a widget. + class drawer + : nana::noncopyable, nana::nonmovable + { + enum{ + event_size = static_cast(event_code::end) + }; + + enum class method_state + { + unknown, + overrided, + not_overrided + }; + public: + ~drawer(); + + void bind(basic_window*); + + void typeface_changed(); + void click(const arg_mouse&); + void dbl_click(const arg_mouse&); + void mouse_enter(const arg_mouse&); + void mouse_move(const arg_mouse&); + void mouse_leave(const arg_mouse&); + void mouse_down(const arg_mouse&); + void mouse_up(const arg_mouse&); + void mouse_wheel(const arg_wheel&); + void mouse_dropfiles(const arg_dropfiles&); + void resizing(const arg_resizing&); + void resized(const arg_resized&); + void move(const arg_move&); + void focus(const arg_focus&); + void key_press(const arg_keyboard&); + void key_char(const arg_keyboard&); + void key_release(const arg_keyboard&); + void shortkey(const arg_keyboard&); + void map(window); //Copy the root buffer to screen + void refresh(); + drawer_trigger* realizer() const; + void attached(widget&, drawer_trigger&); + drawer_trigger* detached(); + public: + void clear(); + void* draw(std::function &&, bool diehard); + void erase(void* diehard); + private: + void _m_bground_pre(); + void _m_bground_end(); + void _m_draw_dynamic_drawing_object(); + void _m_use_refresh(); + + template + void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr) + { + if (realizer_) + { + const int pos = static_cast(evt_code); + if (method_state::not_overrided != mth_state_[pos]) + { + _m_bground_pre(); + + if (method_state::unknown == mth_state_[pos]) + { + realizer_->_m_reset_overrided(); + (realizer_->*mfptr)(graphics, arg); + mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided); + } + else + (realizer_->*mfptr)(graphics, arg); + + _m_use_refresh(); + _m_draw_dynamic_drawing_object(); + _m_bground_end(); + } + } + } + public: + nana::paint::graphics graphics; + private: + basic_window* core_window_{nullptr}; + drawer_trigger* realizer_{nullptr}; + std::vector dynamic_drawing_objects_; + bool refreshing_{false}; + method_state mth_state_[event_size]; + }; + }//end namespace detail +}//end namespace nana + +#endif diff --git a/include/nana/gui/detail/dynamic_drawing_object.hpp b/include/nana/gui/detail/dynamic_drawing_object.hpp new file mode 100644 index 00000000..892d0e56 --- /dev/null +++ b/include/nana/gui/detail/dynamic_drawing_object.hpp @@ -0,0 +1,69 @@ +/* + * Dynamic Drawing Object Implementation + * Copyright(C) 2003-2013 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/gui/detail/dynamic_drawing_object.hpp + * + * !DON'T INCLUDE THIS HEADER FILE IN YOUR SOURCE CODE + */ + +#ifndef NANA_GUI_DETAIL_DYNAMIC_DRAWING_OBJECT_HPP +#define NANA_GUI_DETAIL_DYNAMIC_DRAWING_OBJECT_HPP + +#include +#include + +namespace nana +{ + namespace detail + { + namespace dynamic_drawing + { + class object + { + object(const object&) = delete; + object& operator=(const object&) = delete; + public: + object(){} + virtual ~object(){} + + virtual bool diehard() const + { + return false; + } + + virtual void draw(nana::paint::graphics&) const = 0; + }; + + //user_draw_function + class user_draw_function + : public object + { + public: + user_draw_function(std::function && f, bool diehard) + : diehard_(diehard), fn_(std::move(f)) + {} + + void draw(paint::graphics& graph) const + { + fn_(graph); + } + + bool diehard() const + { + return diehard_; + } + private: + bool diehard_; + std::function fn_; + }; + }//end namespace dynamic_drawing + } +}//end namespace nana + +#endif + diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp new file mode 100644 index 00000000..a3eb42c6 --- /dev/null +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -0,0 +1,152 @@ +#ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP +#define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP +#include +#include +#include + +#include + +namespace nana{ + namespace detail + { + template + class edge_nimbus_renderer + { + edge_nimbus_renderer(){} + public: + typedef CoreWindow core_window_t; + typedef window_layout window_layer; + typedef nana::paint::graphics & graph_reference; + + static edge_nimbus_renderer& instance() + { + static edge_nimbus_renderer object; + return object; + } + + std::size_t weight() const + { + return 2; + } + + bool render(core_window_t * wd) + { + bool rendered = false; + core_window_t * root_wd = wd->root_widget; + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + if(nimbus.size()) + { + core_window_t * focused = root_wd->other.attribute.root->focus; + native_window_type native = root_wd->root; + std::size_t pixels = weight(); + + auto graph = root_wd->root_graph; + + std::vector erase; + std::vector r_set; + nana::rectangle r; + for(auto & action : nimbus) + { + if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r)) + { + if(action.window == wd) + rendered = true; + + r_set.push_back(r); + action.rendered = true; + } + else if(action.rendered) + { + action.rendered = false; + erase.push_back(action.window); + } + } + + //Erase + for(auto el : erase) + { + if(el == wd) + rendered = true; + + r.x = el->pos_root.x - static_cast(pixels); + r.y = el->pos_root.y - static_cast(pixels); + r.width = static_cast(el->dimension.width + (pixels << 1)); + r.height = static_cast(el->dimension.height + (pixels << 1)); + + graph->paste(native, r, r.x, r.y); + } + + auto visual_iterator = r_set.begin(); + //Render + for(auto & action : nimbus) + { + if(action.rendered) + _m_render_edge_nimbus(action.window, *(visual_iterator++)); + } + } + return rendered; + } + private: + static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd) + { + if((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) + return true; + else if((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::over)) + return true; + return false; + } + + void _m_render_edge_nimbus(core_window_t* wd, const nana::rectangle & visual) + { + nana::rectangle r(visual); + r.pare_off(-static_cast(weight())); + nana::rectangle good_r; + if(overlap(r, nana::rectangle(wd->root_graph->size()), good_r)) + { + if( (good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || + (good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height)) + { + auto graph = wd->root_graph; + nana::paint::pixel_buffer pixbuf(graph->handle(), r); + + pixel_rgb_t px0, px1, px2, px3; + + px0 = pixbuf.pixel(0, 0); + px1 = pixbuf.pixel(r.width - 1, 0); + px2 = pixbuf.pixel(0, r.height - 1); + px3 = pixbuf.pixel(r.width - 1, r.height - 1); + + good_r.x = good_r.y = 1; + good_r.width = r.width - 2; + good_r.height = r.height - 2; + pixbuf.rectangle(good_r, wd->color.active, 0.95, false); + + good_r.x = good_r.y = 0; + good_r.width = r.width; + good_r.height = r.height; + pixbuf.rectangle(good_r, wd->color.active, 0.4, false); + + pixbuf.pixel(0, 0, px0); + pixbuf.pixel(r.width - 1, 0, px1); + pixbuf.pixel(0, r.height - 1, px2); + pixbuf.pixel(r.width - 1, r.height - 1, px3); + + pixbuf.paste(wd->root, r.x, r.y); + + std::vector overlaps; + if(window_layer::read_overlaps(wd, visual, overlaps)) + { + for(auto & wdr : overlaps) + graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y); + } + } + else + wd->root_graph->paste(wd->root, visual, visual.x, visual.y); + } + } + }; + } +}//end namespace nana + +#endif diff --git a/include/nana/gui/detail/element_store.hpp b/include/nana/gui/detail/element_store.hpp new file mode 100644 index 00000000..0035d4be --- /dev/null +++ b/include/nana/gui/detail/element_store.hpp @@ -0,0 +1,52 @@ +/* +* The Store for the Storage Of Elements +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/element_store.hpp +*/ + +#ifndef NANA_GUI_DETAIL_ELEMENT_STORE_HPP +#define NANA_GUI_DETAIL_ELEMENT_STORE_HPP + +#include +#include +#include +#include + +namespace nana +{ +namespace detail +{ + class element_store + { + typedef ::nana::element::element_interface element_interface; + typedef pat::cloneable< ::nana::element::element_interface> cloneable_element; + + struct data + { + cloneable_element object; + ::nana::element::element_interface * fast_ptr; + + data(); + }; + + struct store + { + std::map table; + }; + public: + element_interface * const * bground(const std::string&); + void bground(const std::string&, const pat::cloneable&); + void bground(const std::string&, pat::cloneable&&); + private: + store bground_; + }; +}//end namespace detail +} + +#endif diff --git a/include/nana/gui/detail/event_code.hpp b/include/nana/gui/detail/event_code.hpp new file mode 100644 index 00000000..2f126db6 --- /dev/null +++ b/include/nana/gui/detail/event_code.hpp @@ -0,0 +1,48 @@ +/* +* Definitions of General Events Code +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 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/gui/detail/event_code.hpp +* +*/ + +#ifndef NANA_DETAIL_EVENT_CODE_HPP +#define NANA_DETAIL_EVENT_CODE_HPP + +namespace nana +{ + enum class event_code + { + click, ///< A mouse click event. + dbl_click, ///< A mouse double click event. + mouse_enter, ///< A mouse enters a widget. + mouse_move, ///< A mouse moves over a widget. + mouse_leave, ///< A mouse leaves a widget. + mouse_down, ///< A mouse button is pressed on a widget. + mouse_up, ///< A mouse button is released on a widget. + mouse_wheel, ///< A mouse scrolls the wheel on a widget. + mouse_drop, ///< A mouse release over a window that is registered as recipient of drag and drop. + expose, ///< + resizing, ///< A widget's size is sizing. In this event, A widget's size can be overrided with a new size. + resized, ///< A widget's size is changing. + move, ///< + unload, ///< A form is closed by clicking the X button, only works for root widget. + destroy, ///< A widget is about to be destroyed. + focus, ///< A widget's focus is changed. + key_press, ///< A keyboard is pressed on a focus widget. + key_char, ///< The focus widget received a character. + key_release, ///< A keyboard is released on a focus widget. + shortkey, ///< The widgets received a shortkey message. + + elapse, ///< Unoperational events? . A widget received a tick that is sended by timer. + + end ///< End indicator, it's not an event. + }; +}//end namespace nana + +#endif \ No newline at end of file diff --git a/include/nana/gui/detail/events_holder.hpp b/include/nana/gui/detail/events_holder.hpp new file mode 100644 index 00000000..23b5aae0 --- /dev/null +++ b/include/nana/gui/detail/events_holder.hpp @@ -0,0 +1,20 @@ +#ifndef NANA_DETAIL_EVENTS_HOLDER_HPP +#define NANA_DETAIL_EVENTS_HOLDER_HPP +#include + +namespace nana +{ + struct general_events; + + namespace detail + { + class events_holder + { + public: + virtual ~events_holder(){} + virtual bool set_events(const std::shared_ptr&) = 0; + virtual general_events* get_events() const = 0; + }; + }//end namespace detail +}//end namespace nana +#endif diff --git a/include/nana/gui/detail/events_operation.hpp b/include/nana/gui/detail/events_operation.hpp new file mode 100644 index 00000000..29c65430 --- /dev/null +++ b/include/nana/gui/detail/events_operation.hpp @@ -0,0 +1,35 @@ +#ifndef NANA_DETAIL_EVENTS_OPERATION_HPP +#define NANA_DETAIL_EVENTS_OPERATION_HPP + +#include +#include +#include + +#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) + #include +#else + #include +#endif + +namespace nana +{ + namespace detail + { + class events_operation + { + public: + void make(window, const std::shared_ptr &); + void umake(window); + void register_evt(event_handle); + void cancel(event_handle); + void erase(event_handle); + std::size_t size() const; + private: + mutable std::recursive_mutex mutex_; + std::unordered_set register_; + std::unordered_map> evt_table_; + }; + }//end namespace detail +}//end namespace nana + +#endif diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp new file mode 100644 index 00000000..486373d8 --- /dev/null +++ b/include/nana/gui/detail/general_events.hpp @@ -0,0 +1,497 @@ +/* +* Definition of General Events +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/general_events.hpp +*/ +#ifndef NANA_DETAIL_GENERAL_EVENTS_HPP +#define NANA_DETAIL_GENERAL_EVENTS_HPP + +#include +#include "event_code.hpp" +#include "internal_scope_guard.hpp" +#include +#include +#include +#include +#include + +namespace nana +{ + namespace detail + { + class event_interface + { + public: + virtual ~event_interface(){} + virtual void remove(event_handle) = 0; + }; + + class docker_interface + { + public: + virtual ~docker_interface(){} + virtual event_interface* get_event() const = 0; + }; + + class event_arg_interface + { + public: + virtual ~event_arg_interface(){} + }; + + void events_operation_register(event_handle); + void events_operation_cancel(event_handle); + }//end namespace detail + + struct general_events; + + template + class basic_event : public detail::event_interface + { + public: + typedef const typename std::remove_reference::type & arg_reference; + private: + struct docker + : public detail::docker_interface + { + basic_event * const event_ptr; + std::function invoke; + bool flag_entered = false; + bool flag_deleted = false; + + docker(basic_event * s, std::function && ivk) + : event_ptr(s), invoke(std::move(ivk)) + {} + + docker(basic_event * s, const std::function & ivk) + : event_ptr(s), invoke(ivk) + {} + + ~docker() + { + detail::events_operation_cancel(reinterpret_cast(this)); + } + + detail::event_interface * get_event() const override + { + return event_ptr; + } + }; + public: + template + event_handle connect_front(Function && fn) + { + internal_scope_guard lock; + if (nullptr == dockers_) + dockers_.reset(new std::vector>); + + typedef typename std::remove_reference::type prototype; + std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)))); + auto evt = reinterpret_cast(static_cast(dck.get())); + dockers_->emplace(dockers_->begin(), std::move(dck)); + detail::events_operation_register(evt); + return evt; + } + + event_handle connect(void (*fn)(arg_reference)) + { + return connect([fn](arg_reference arg){ + fn(arg); + }); + } + + template + event_handle connect(Function && fn) + { + internal_scope_guard lock; + if (nullptr == dockers_) + dockers_.reset(new std::vector>); + + typedef typename std::remove_reference::type prototype; + std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)))); + auto evt = reinterpret_cast(static_cast(dck.get())); + dockers_->emplace_back(std::move(dck)); + detail::events_operation_register(evt); + return evt; + } + + template + event_handle operator()(Function&& fn) + { + return connect(std::forward(fn)); + } + + std::size_t length() const + { + internal_scope_guard lock; + return (nullptr == dockers_ ? 0 : dockers_->size()); + } + + void emit(arg_reference& arg) const + { + internal_scope_guard lock; + if (nullptr == dockers_) + return; + + //Make a copy to allow create/destroy a new event handler when the call of emit in an event. + const std::size_t fixed_size = 10; + docker* fixed_buffer[fixed_size]; + docker** transitory = fixed_buffer; + + std::unique_ptr variable_buffer; + auto& dockers = *dockers_; + if (dockers.size() > fixed_size) + { + variable_buffer.reset(new docker*[dockers.size()]); + transitory = variable_buffer.get(); + } + + auto output = transitory; + for (auto & dck : dockers) + { + (*output++) = dck.get(); + } + + for (; transitory != output; ++transitory) + { + std::unique_ptr p(*transitory); + auto i = std::find(dockers.begin(), dockers.end(), p); + if (i != dockers.end()) + { + (*transitory)->flag_entered = true; + (*transitory)->invoke(arg); + (*transitory)->flag_entered = false; + + if ((*transitory)->flag_deleted) + dockers.erase(i); + } + p.release(); + } + } + + void clear() + { + internal_scope_guard lock; + if (dockers_) + dockers_.reset(); + } + + void remove(event_handle evt) + { + internal_scope_guard lock; + if (dockers_) + { + auto i = std::find_if(dockers_->begin(), dockers_->end(), [evt](const std::unique_ptr& sp) + { + return (reinterpret_cast(evt) == sp.get()); + }); + + if (i != dockers_->end()) + { + if (i->get()->flag_entered) + i->get()->flag_deleted = true; + else + dockers_->erase(i); + } + } + } + private: + template + struct factory + { + static std::function build(Fn && fn) + { + return std::move(fn); + } + + static std::function build(const Fn & fn) + { + return fn; + } + }; + + template + struct factory + { + typedef typename std::remove_reference::type arg_type; + typedef typename std::remove_reference::type fn_type; + + template + static std::function build(Tfn && fn) + { + typedef typename std::remove_reference::type type; + return build_second(std::forward(fn), &type::operator()); + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)()) + { + return [fn](arg_reference) mutable + { + fn(); + }; + } + + static std::function build_second(fn_type&& fn, void(fn_type::*)(arg_reference)) + { + return std::move(fn); + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)()const) + { + return [fn](arg_reference) mutable + { + fn(); + }; + } + + static std::function build_second(fn_type&& fn, void(fn_type::*)(arg_reference) const) + { + return std::move(fn); + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)(Arg2)) + { + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + return[fn](arg_reference arg) mutable + { + fn(arg); + }; + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)(Arg2)const) + { + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + return [fn](arg_reference arg) mutable + { + fn(arg); + }; + } + }; + + template + struct factory < std::function, false> + { + typedef typename std::remove_reference::type arg_type; + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + + static std::function build(const std::function& fn) + { + return [fn](arg_reference arg) mutable{ + fn(arg); + }; + } + + static std::function build_second(std::function && fn) + { + return std::move(fn); + } + }; + + template + struct factory < std::function, false> + { + static std::function build(const std::function& fn) + { + return[fn](arg_reference) mutable{ + fn(); + }; + } + }; + + template + struct factory < Ret(*)(), false> + { + static std::function build(Ret(*fn)()) + { + return[fn](arg_reference) mutable{ + fn(); + }; + } + }; + + template + struct factory < Ret(*)(Arg2), false> + { + typedef typename std::remove_reference::type arg_type; + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + + static std::function build(Ret(*fn)(Arg2)) + { + return[fn](arg_reference arg) mutable { + fn(arg); + }; + } + }; + + template + struct factory < Ret(), false> + { + static std::function build(Ret(*fn)()) + { + return[fn](arg_reference){ + fn(); + }; + } + }; + + template + struct factory < Ret(Arg2), false> + { + typedef typename std::remove_reference::type arg_type; + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + + static std::function build(Ret(*fn)(Arg)) + { + return[fn](arg_reference arg){ + fn(arg); + }; + } + }; + private: + std::unique_ptr>> dockers_; + }; + + struct arg_mouse + : public detail::event_arg_interface + { + event_code evt_code; + ::nana::window window_handle; + ::nana::point pos; + bool left_button; + bool mid_button; + bool right_button; + bool shift; + bool ctrl; + }; + + struct arg_wheel : public arg_mouse + { + enum class wheel{ + vertical, + horizontal + }; + + wheel which; /// files; + }; + + struct arg_expose : public detail::event_arg_interface + { + ::nana::window window_handle; + bool exposed; + }; + + struct arg_focus : public detail::event_arg_interface + { + ::nana::window window_handle; + ::nana::native_window_type receiver; + bool getting; + }; + + struct arg_keyboard : public detail::event_arg_interface + { + event_code evt_code; + ::nana::window window_handle; + mutable nana::char_t key; + mutable bool ignore; + bool ctrl; + bool shift; + }; + + struct arg_move : public detail::event_arg_interface + { + ::nana::window window_handle; + int x; + int y; + }; + + struct arg_resized : public detail::event_arg_interface + { + ::nana::window window_handle; + unsigned width; + unsigned height; + }; + + struct arg_resizing : public detail::event_arg_interface + { + ::nana::window window_handle; + window_border border; + mutable unsigned width; + mutable unsigned height; + }; + + struct arg_unload : public detail::event_arg_interface + { + ::nana::window window_handle; + mutable bool cancel; + }; + + struct arg_destroy : public detail::event_arg_interface + { + ::nana::window window_handle; + }; + + struct general_events + { + virtual ~general_events(){} + basic_event mouse_enter; + basic_event mouse_move; + basic_event mouse_leave; + basic_event mouse_down; + basic_event mouse_up; + basic_event click; + basic_event dbl_click; + basic_event mouse_wheel; + basic_event mouse_dropfiles; + basic_event expose; + basic_event focus; + basic_event key_press; + basic_event key_release; + basic_event key_char; + basic_event shortkey; + + basic_event move; + basic_event resizing; + basic_event resized; + basic_event destroy; + }; + + namespace detail + { + struct events_root_extension + : public general_events + { + basic_event unload; + }; + }//end namespace detail + + namespace dev + { + template + struct event_mapping + { + typedef general_events type; + }; + }//end namespace dev + +}//end namespace nana + +#endif diff --git a/include/nana/gui/detail/handle_manager.hpp b/include/nana/gui/detail/handle_manager.hpp new file mode 100644 index 00000000..33bb97a6 --- /dev/null +++ b/include/nana/gui/detail/handle_manager.hpp @@ -0,0 +1,287 @@ +/* + * Handle Manager Implementation + * Copyright(C) 2003-2013 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/gui/detail/handle_manager.hpp + * + * @description: + * this manages all the window handles + */ + +#ifndef NANA_GUI_DETAIL_HANDLE_MANAGER_HPP +#define NANA_GUI_DETAIL_HANDLE_MANAGER_HPP + +#include +#include +#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) + #include +#else + #include +#endif + +#include +#include +#include + +namespace nana +{ + namespace detail + { + template + class cache + : noncopyable + { + public: + typedef Key key_type; + typedef Value value_type; + typedef std::pair pair_type; + typedef std::size_t size_type; + + cache() + :addr_(reinterpret_cast(::operator new(sizeof(pair_type) * CacheSize))) + { + for(std::size_t i = 0; i < CacheSize; ++i) + { + bitmap_[i] = 0; + seq_[i] = nana::npos; + } + } + + ~cache() + { + for(std::size_t i = 0; i < CacheSize; ++i) + { + if(bitmap_[i]) + addr_[i].~pair_type(); + } + + ::operator delete(addr_); + } + + bool insert(key_type k, value_type v) + { + size_type pos = _m_find_key(k); + if(pos != nana::npos) + { + addr_[pos].second = v; + } + else + { + //No key exists + pos = _m_find_pos(); + + if(pos == nana::npos) + { //No room, and remove the last pair + pos = seq_[CacheSize - 1]; + (addr_ + pos)->~pair_type(); + } + + if(seq_[0] != nana::npos) + {//Need to move + for(int i = CacheSize - 1; i > 0; --i) + seq_[i] = seq_[i - 1]; + } + + seq_[0] = pos; + + new (addr_ + pos) pair_type(k, v); + bitmap_[pos] = 1; + } + return v; + } + + value_type * get(key_type k) + { + size_type pos = _m_find_key(k); + if(pos != nana::npos) + return &(addr_[pos].second); + return 0; + } + private: + size_type _m_find_key(key_type k) const + { + for(std::size_t i = 0; i < CacheSize; ++i) + { + if(bitmap_[i] && (addr_[i].first == k)) + return i; + } + return nana::npos; + } + + size_type _m_find_pos() const + { + for(std::size_t i = 0; i < CacheSize; ++i) + { + if(bitmap_[i] == 0) + return i; + } + return nana::npos; + } + private: + char bitmap_[CacheSize]; + size_type seq_[CacheSize]; + pair_type * addr_; + }; + + //handle_manager + //@brief + // handle_manager maintains handles of a type. removing a handle dose not destroy it, + // it will be inserted to a trash queue for deleting at a safe time. + // For efficiency, this class is not a thread-safe. + template + class handle_manager + : nana::noncopyable + { + public: + typedef HandleType handle_type; + typedef Condition cond_type; + typedef Deleter deleter_type; + typedef std::map handle_map_t; + typedef std::pair holder_pair; + + ~handle_manager() + { + delete_trash(0); + } + + void insert(handle_type handle, unsigned tid) + { + std::lock_guard lock(mutex_); + + holder_[handle] = tid; + + is_queue::value, std::vector >::insert(handle, queue_); + cacher_.insert(handle, true); + } + + void operator()(const handle_type handle) + { + remove(handle); + } + + void remove(const handle_type handle) + { + std::lock_guard lock(mutex_); + + auto i = static_cast(holder_).find(handle); + if(holder_.cend() != i) + { + is_queue::value, std::vector >::erase(handle, queue_); + cacher_.insert(handle, false); + trash_.emplace_back(i->first, i->second); + holder_.erase(i); + } + } + + void delete_trash(unsigned tid) + { + std::lock_guard lock(mutex_); + + if(trash_.size()) + { + deleter_type del_functor; + if(tid == 0) + { + for(auto & m : trash_) + del_functor(m.first); + trash_.clear(); + } + else + { + for(auto i = trash_.begin(), end = trash_.end(); i != end;) + { + if(tid == i->second) + { + del_functor(i->first); + i = trash_.erase(i); + end = trash_.end(); + } + else + ++i; + } + } + } + } + + handle_type last() const + { + std::lock_guard lock(mutex_); + if(queue_.size()) + return queue_.back(); + return handle_type(); + } + + std::size_t size() const + { + return holder_.size(); + } + + handle_type get(unsigned index) const + { + std::lock_guard lock(mutex_); + if(index < queue_.size()) + return queue_[index]; + return handle_type(); + } + + bool available(const handle_type handle) const + { + if (nullptr == handle) + return false; + + std::lock_guard lock(mutex_); + bool * v = cacher_.get(handle); + if(v) return *v; + return cacher_.insert(handle, (holder_.count(handle) != 0)); + } + + void all(std::vector & v) const + { + std::lock_guard lock(mutex_); + std::copy(queue_.cbegin(), queue_.cend(), std::back_inserter(v)); + } + private: + + template + struct is_queue + { + public: + static void insert(handle_type handle, Container& queue) + { + if(cond_type::is_queue(handle)) + queue.push_back(handle); + } + + static void erase(handle_type handle, Container& queue) + { + if(cond_type::is_queue(handle)) + { + auto i = std::find(queue.begin(), queue.end(), handle); + if(i != queue.end()) + queue.erase(i); + } + } + }; + + template + struct is_queue + { + public: + static void insert(handle_type handle, Container& queue){} + static void erase(handle_type handle, Container& queue){} + }; + + private: + mutable std::recursive_mutex mutex_; + mutable cache cacher_; + handle_map_t holder_; + std::vector queue_; + std::vector trash_; + };//end class handle_manager + }//end namespace detail +}// end namespace nana +#endif diff --git a/include/nana/gui/detail/inner_fwd.hpp b/include/nana/gui/detail/inner_fwd.hpp new file mode 100644 index 00000000..00a1f24e --- /dev/null +++ b/include/nana/gui/detail/inner_fwd.hpp @@ -0,0 +1,55 @@ +/* +* Inner Forward Declaration +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/inner_fwd.hpp +* +*/ + +#ifndef NANA_GUI_INNER_FWD_HPP +#define NANA_GUI_INNER_FWD_HPP + +#include + +namespace nana{ + namespace detail + { + struct signals + { + enum class code + { + caption, + read_caption, + destroy, + size, + end + }; + + union + { + const nana::char_t* caption; + nana::string * str; + struct + { + unsigned width; + unsigned height; + }size; + }info; + }; + + class signal_invoker_interface + { + public: + virtual ~signal_invoker_interface() + {} + + virtual void call_signal(signals::code, const signals&) = 0; + }; + } +} +#endif //NANA_GUI_INNER_FWD_HPP diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp new file mode 100644 index 00000000..31b59733 --- /dev/null +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -0,0 +1,201 @@ +/* + * Implementations of Inner Forward Declaration + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/inner_fwd_implement.hpp + * + */ + +#ifndef NANA_GUI_INNER_FWD_IMPLEMENT_HPP +#define NANA_GUI_INNER_FWD_IMPLEMENT_HPP + +#include "inner_fwd.hpp" +#include "basic_window.hpp" +#include "../../paint/graphics.hpp" + +#include +#include + +namespace nana{ + namespace detail + { + class shortkey_container + { + struct item_type + { + window handle; + std::vector keys; + }; + public: + void clear() + { + keybase_.clear(); + } + + bool make(window wd, unsigned long key) + { + if (wd == nullptr) return false; + if (key < 0x61) key += (0x61 - 0x41); + + for (auto & m : keybase_) + { + if (m.handle == wd) + { + m.keys.push_back(key); + return true; + } + } + + item_type m; + m.handle = wd; + m.keys.push_back(key); + keybase_.push_back(m); + + return true; + } + + void umake(window wd) + { + if (wd == nullptr) return; + auto i = std::find_if(keybase_.begin(), keybase_.end(), [wd](const item_type& m){ + return (m.handle == wd); + }); + + if (i != keybase_.end()) + keybase_.erase(i); + } + + std::vector keys(window wd) const + { + std::vector v; + if (wd) + { + for (auto & m : keybase_) + { + if (m.handle == wd) + { + v = m.keys; + break; + } + } + } + return v; + + } + + window find(unsigned long key) const + { + if (key < 0x61) key += (0x61 - 0x41); + + for (auto & m : keybase_) + { + for (auto n : m.keys) + { + if (key == n) + return m.handle; + } + } + return nullptr; + } + private: + std::vector keybase_; + }; + + + struct root_misc + { + typedef basic_window core_window_t; + + core_window_t * window; + nana::paint::graphics root_graph; + shortkey_container shortkeys; + + struct condition_tag + { + core_window_t* pressed{nullptr}; //The handle to a window which is being pressed + core_window_t* hovered{nullptr}; //the latest window that mouse moved + bool tabstop_focus_changed{false}; //KeyDown may set it true, if it is true KeyChar will ignore the message + }condition; + + root_misc(core_window_t * wd, unsigned width, unsigned height) + : window(wd), + root_graph(width, height) + {} + };//end struct root_misc + + class root_register + { + public: + root_misc* insert(native_window_type wd, const root_misc& misc) + { + recent_ = wd; + auto ret = table_.insert(std::make_pair(wd, misc)); + misc_ptr_ = &(ret.first->second); + return misc_ptr_; + } + + root_misc * find(native_window_type wd) + { + if (wd == recent_) + return misc_ptr_; + + recent_ = wd; + + auto i = table_.find(wd); + if (i != table_.end()) + misc_ptr_ = &(i->second); + else + misc_ptr_ = nullptr; + + return misc_ptr_; + } + + void erase(native_window_type wd) + { + table_.erase(wd); + recent_ = wd; + misc_ptr_ = nullptr; + } + private: + //Cached + mutable native_window_type recent_{nullptr}; + mutable root_misc * misc_ptr_{nullptr}; + + std::map table_; + }; + + + class signal_manager + { + typedef basic_window core_window_t; + public: + void make(core_window_t* wd, signal_invoker_interface* si) + { + if (si) + table_[wd].reset(si); + else + table_.erase(wd); + } + + void umake(core_window_t * wd) + { + table_.erase(wd); + } + + void call_signal(core_window_t * wd, signals::code code, const signals& s) + { + auto i = table_.find(wd); + if (i != table_.end()) + i->second->call_signal(code, s); + } + private: + std::map> table_; + }; + } +}//end namespace nana +#endif //NANA_GUI_INNER_FWD_IMPLEMENT_HPP diff --git a/include/nana/gui/detail/internal_scope_guard.hpp b/include/nana/gui/detail/internal_scope_guard.hpp new file mode 100644 index 00000000..c4bdaaf6 --- /dev/null +++ b/include/nana/gui/detail/internal_scope_guard.hpp @@ -0,0 +1,31 @@ +/* +* Forward Declaration of Internal Scope Guard +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/internal_scope_guard.hpp +*/ +#ifndef NANA_GUI_DETAIL_INTERNAL_SCOPE_GUARD_HPP +#define NANA_GUI_DETAIL_INTERNAL_SCOPE_GUARD_HPP + +namespace nana +{ + //Implemented in bedrock + class internal_scope_guard + { + internal_scope_guard(const internal_scope_guard&) = delete; + internal_scope_guard(internal_scope_guard&&) = delete; + + internal_scope_guard& operator=(const internal_scope_guard&) = delete; + internal_scope_guard& operator=(internal_scope_guard&&) = delete; + public: + internal_scope_guard(); + ~internal_scope_guard(); + }; +} + +#endif \ No newline at end of file diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp new file mode 100644 index 00000000..fca2b828 --- /dev/null +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -0,0 +1,89 @@ +/* + * Platform Implementation + * Copyright(C) 2003-2013 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/gui/detail/native_window_interface.hpp + */ + +#ifndef NANA_GUI_DETAIL_NATIVE_WINDOW_INTERFACE_HPP +#define NANA_GUI_DETAIL_NATIVE_WINDOW_INTERFACE_HPP + +#include "../basis.hpp" +#include + +namespace nana +{ +namespace detail +{ + + struct native_interface + { + struct window_result + { + native_window_type native_handle; + + unsigned width; //client size + unsigned height; //client size + + unsigned extra_width; //extra border size, it is useful in Windows, ignore in X11 always 0 + unsigned extra_height; //extra border size, it is useful in Windows, ignore in X11 always 0 + }; + + static nana::size screen_size(); + static rectangle screen_area_from_point(const point&); + static window_result create_window(native_window_type, bool nested, const rectangle&, const appearance&); + static native_window_type create_child_window(native_window_type, const rectangle&); + +#if defined(NANA_X11) + static void set_modal(native_window_type); +#endif + static void enable_dropfiles(native_window_type, bool); + static void enable_window(native_window_type, bool); + static bool window_icon(native_window_type, const paint::image&); + static void activate_owner(native_window_type); + static void activate_window(native_window_type); + static void close_window(native_window_type); + static void show_window(native_window_type, bool show, bool active); + static void restore_window(native_window_type); + static void zoom_window(native_window_type, bool ask_for_max); + static void refresh_window(native_window_type); + static bool is_window(native_window_type); + static bool is_window_visible(native_window_type); + static bool is_window_zoomed(native_window_type, bool ask_for_max); + + static nana::point window_position(native_window_type); + static void move_window(native_window_type, int x, int y); + static void move_window(native_window_type, const rectangle&); + static void bring_to_top(native_window_type); + static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after); + + static void window_size(native_window_type, const size&); + static void get_window_rect(native_window_type, rectangle&); + static void window_caption(native_window_type, const nana::string&); + static nana::string window_caption(native_window_type); + static void capture_window(native_window_type, bool); + static nana::point cursor_position(); + static native_window_type get_owner_window(native_window_type); + //For Caret + static void caret_create(native_window_type, unsigned width, unsigned height); + static void caret_destroy(native_window_type); + static void caret_pos(native_window_type, int x, int y); + static void caret_visible(native_window_type, bool); + + static void set_focus(native_window_type); + static native_window_type get_focus_window(); + static bool calc_screen_point(native_window_type, nana::point&); + static bool calc_window_point(native_window_type, nana::point&); + + static native_window_type find_window(int x, int y); + static nana::size check_track_size(nana::size sz, unsigned extra_width, unsigned extra_height, bool true_for_max); + }; + + +}//end namespace detail +}//end namespace nana +#endif diff --git a/include/nana/gui/detail/runtime_manager.hpp b/include/nana/gui/detail/runtime_manager.hpp new file mode 100644 index 00000000..9a2fb3c8 --- /dev/null +++ b/include/nana/gui/detail/runtime_manager.hpp @@ -0,0 +1,100 @@ +/* + * A Runtime Manager Implementation + * Copyright(C) 2003-2013 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/gui/detail/runtime_manager.hpp + * + */ +#ifndef NANA_GUI_DETAIL_RUNTIME_MANAGER_HPP +#define NANA_GUI_DETAIL_RUNTIME_MANAGER_HPP + +#include + +namespace nana +{ + namespace detail + { + template + class runtime_manager + { + public: + typedef Window window_handle; + + template + Form* create_form(Args&&... args) + { + widget_placer
* holder = new widget_placer; + if (holder->create(std::forward(args)...)) + { + holder_[holder->get_handle()] = holder; + return holder->get(); + } + + delete holder; + return nullptr; + } + + void remove_if_exists(window_handle wd) + { + auto i = holder_.find(wd); + if(i != holder_.cend()) + { + delete i->second; + holder_.erase(i); + } + } + private: + class widget_holder + { + public: + virtual ~widget_holder(){} + virtual window_handle get_handle() const = 0; + }; + + template + class widget_placer : public widget_holder + { + public: + widget_placer() + : form_(nullptr) + {} + + ~widget_placer() + { + delete form_; + } + + template + bool create(Args&&... args) + { + if (nullptr == form_) + form_ = new Form(std::forward(args)...); + + return (form_ && !form_->empty()); + } + + Form* get() const + { + return form_; + } + + window_handle get_handle() const override + { + return reinterpret_cast(form_ ? form_->handle() : nullptr); + } + private: + Form * form_; + }; + private: + std::map holder_; + }; //end class runtime_manager + + }//end namespace detail +}//end namespace nana + + +#endif diff --git a/include/nana/gui/detail/window_layout.hpp b/include/nana/gui/detail/window_layout.hpp new file mode 100644 index 00000000..f4bdfe0b --- /dev/null +++ b/include/nana/gui/detail/window_layout.hpp @@ -0,0 +1,88 @@ +/* + * Window Layout Implementation + * Copyright(C) 2003-2013 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/gui/detail/window_layout.hpp + * + */ + +#ifndef NANA_GUI_DETAIL_WINDOW_LAYOUT_HPP +#define NANA_GUI_DETAIL_WINDOW_LAYOUT_HPP + +#include +#include + +namespace nana +{ + namespace paint + { + class image; + class graphics; + } +} + +namespace nana{ +namespace detail +{ + struct basic_window; + + //class window_layout + class window_layout + { + public: + typedef basic_window core_window_t; + + struct wd_rectangle + { + core_window_t * window; + rectangle r; + }; + public: + static void paint(core_window_t*, bool is_redraw, bool is_child_refreshed); + + static bool maproot(core_window_t*, bool have_refreshed, bool is_child_refreshed); + + static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph); + + //read_visual_rectangle + //@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, + // the visual rectangle is a rectangular block that a window should be displayed on screen. + // The result is a rectangle that is a visible area for its ancesters. + static bool read_visual_rectangle(core_window_t*, nana::rectangle& visual); + + //read_overlaps + // reads the overlaps that are overlapped a rectangular block + static bool read_overlaps(core_window_t*, const nana::rectangle& vis_rect, std::vector& blocks); + + static bool enable_effects_bground(core_window_t *, bool enabled); + + //make_bground + // update the glass buffer of a glass window. + static void make_bground(core_window_t* const); + private: + + //_m_paste_children + //@brief:paste children window to the root graphics directly. just paste the visual rectangle + static void _m_paste_children(core_window_t*, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); + + static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); + + //_m_notify_glasses + //@brief: Notify the glass windows that are overlapped with the specified vis_rect + static void _m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& r_visual); + private: + struct data_section + { + std::vector effects_bground_windows; + }; + static data_section data_sect; + };//end class window_layout +}//end namespace detail +}//end namespace nana + +#endif //NANA_GUI_DETAIL_WINDOW_LAYOUT_HPP + diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp new file mode 100644 index 00000000..baab1232 --- /dev/null +++ b/include/nana/gui/detail/window_manager.hpp @@ -0,0 +1,225 @@ +/* + * Window Manager Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/window_manager.hpp + * + * + * destroy method destroys a window handle and the handles of its children, but it doesn't delete the handle which type is a root window or a frame + * destroy_handle method just destroys the handle which type is a root window or a frame + * + */ + +#ifndef NANA_GUI_DETAIL_WINDOW_MANAGER_HPP +#define NANA_GUI_DETAIL_WINDOW_MANAGER_HPP + +#include +#include "window_layout.hpp" +#include "event_code.hpp" +#include "inner_fwd.hpp" +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) + #include +#else + #include +#endif + +namespace nana +{ + class widget; //forward declaration + namespace paint + { + class image; + } +} + +namespace nana{ +namespace detail +{ + template + class signal_invoker_mf + : public signal_invoker_interface + { + public: + signal_invoker_mf(T& obj, void(T::*mf)(signals::code, const signals&)) + : obj_(obj), + mf_(mf) + {} + + void call_signal(signals::code code, const signals& s) override + { + (obj_.*mf_)(code, s); + } + private: + T& obj_; + void(T::*mf_)(signals::code, const signals&); + }; + + struct root_misc; + + class window_manager + { + class revertible_mutex + : public std::recursive_mutex + { + struct thr_refcnt + { + unsigned tid; + std::size_t refcnt; + }; + public: + revertible_mutex(); + + void lock(); + bool try_lock(); + void unlock(); + + void revert(); + void forward(); + private: + thr_refcnt thr_; + std::vector stack_; + }; + public: + typedef native_window_type native_window; + typedef revertible_mutex mutex_type; + + typedef basic_window core_window_t; + typedef std::vector cont_type; + + typedef window_layout wndlayout_type; + + window_manager(); + ~window_manager(); + + static bool is_queue(core_window_t*); + std::size_t number_of_core_window() const; + mutex_type & internal_lock() const; + void all_handles(std::vector&) const; + + template + void attach_signal(core_window_t* wd, T& obj, void(Concept::*mf)(signals::code, const signals&)) + { + return _m_attach_signal(wd, new signal_invoker_mf(obj, mf)); + } + + void signal_fire_caption(core_window_t*, const nana::char_t*); + nana::string signal_fire_caption(core_window_t*); + void event_filter(core_window_t*, bool is_make, event_code); + void default_icon(const nana::paint::image&); + + bool available(core_window_t*); + bool available(core_window_t *, core_window_t*); + bool available(native_window_type); + + core_window_t* create_root(core_window_t* owner, bool nested, rectangle, const appearance&, widget*); + core_window_t* create_widget(core_window_t* parent, const rectangle&, bool is_lite, widget*); + core_window_t* create_frame(core_window_t* parent, const rectangle&, widget*); + bool insert_frame(core_window_t* frame, native_window); + bool insert_frame(core_window_t* frame, core_window_t*); + void close(core_window_t*); + + //destroy + //@brief: Delete the window handle + void destroy(core_window_t*); + + //destroy_handle + //@brief: Delete window handle, the handle type must be a root and a frame. + void destroy_handle(core_window_t*); + + void icon(core_window_t*, const paint::image&); + + //show + //@brief: show or hide a window + bool show(core_window_t* wd, bool visible); + + core_window_t* find_window(native_window_type root, int x, int y); + + //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window + bool move(core_window_t*, int x, int y, bool passive); + bool move(core_window_t*, const rectangle&); + + bool size(core_window_t*, nana::size, bool passive, bool ask_update); + + core_window_t* root(native_window_type) const; + + //Copy the root buffer that wnd specified into DeviceContext + void map(core_window_t*); + + bool update(core_window_t*, bool redraw, bool force); + void refresh_tree(core_window_t*); + + bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen); + + bool get_graphics(core_window_t*, nana::paint::graphics&); + bool get_visual_rectangle(core_window_t*, nana::rectangle&); + + ::nana::widget* get_widget(core_window_t*) const; + std::vector get_children(core_window_t*) const; + bool set_parent(core_window_t* wd, core_window_t* new_parent); + core_window_t* set_focus(core_window_t*, bool root_has_been_focused); + + core_window_t* capture_redirect(core_window_t*); + void capture_ignore_children(bool ignore); + bool capture_window_entered(int root_x, int root_y, bool& prev); + core_window_t * capture_window() const; + core_window_t* capture_window(core_window_t*, bool value); + + void enable_tabstop(core_window_t*); + core_window_t* tabstop(core_window_t*, bool forward) const; //forward means move to next in logic. + + void remove_trash_handle(unsigned tid); + + bool enable_effects_bground(core_window_t*, bool); + + bool calc_window_point(core_window_t*, nana::point&); + + root_misc* root_runtime(native_window_type) const; + + bool register_shortkey(core_window_t*, unsigned long key); + void unregister_shortkey(core_window_t*, bool with_children); + std::vector> shortkeys(core_window_t*, bool with_children); + + core_window_t* find_shortkey(native_window_type, unsigned long key); + private: + void _m_attach_signal(core_window_t*, signal_invoker_interface*); + void _m_disengage(core_window_t*, core_window_t* for_new); + void _m_destroy(core_window_t*); + void _m_move_core(core_window_t*, const point& delta); + core_window_t* _m_find(core_window_t*, const point&); + static bool _m_effective(core_window_t*, const point& root_pos); + private: + mutable mutex_type mutex_; + + struct wdm_private_impl; + wdm_private_impl * const impl_; + + signals signals_; + + struct attribute + { + struct captured + { + core_window_t *window; + bool inside; + bool ignore_children; + std::vector > history; + }capture; + }attr_; + + struct menu_tag + { + native_window_type window; + native_window_type owner; + bool has_keyboard; + }menu_; + };//end class window_manager +}//end namespace detail +}//end namespace nana +#endif diff --git a/include/nana/gui/dragger.hpp b/include/nana/gui/dragger.hpp new file mode 100644 index 00000000..9846b672 --- /dev/null +++ b/include/nana/gui/dragger.hpp @@ -0,0 +1,29 @@ +#ifndef NANA_GUI_DRAGGER_HPP +#define NANA_GUI_DRAGGER_HPP +#include "programming_interface.hpp" + +namespace nana +{ + /// \brief Helper class that allows the user to drag windows. + /// + /// If a user presses the mouse on the specified window and moves the mouse, the specified window is dragged. + /// The drag target window and trigger window can be set more than once. + /// See [Is it possible to make event inside event handler?](https://nanapro.codeplex.com/discussions/444121) + /// and [How to make widget movable by mouse the best way](https://nanapro.codeplex.com/discussions/444058) + + class dragger + : nana::noncopyable + { + class dragger_impl_t; + public: + dragger(); + ~dragger(); + void target(window); + void target(window, const rectangle& restrict_area, nana::arrange); + void remove_target(window); + void trigger(window); + private: + dragger_impl_t * impl_; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/drawing.hpp b/include/nana/gui/drawing.hpp new file mode 100644 index 00000000..fb1b966b --- /dev/null +++ b/include/nana/gui/drawing.hpp @@ -0,0 +1,49 @@ +/* + * A Drawing Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/drawing.hpp + */ +#ifndef NANA_GUI_DRAWING_HPP +#define NANA_GUI_DRAWING_HPP +#include "widgets/widget.hpp" +#include "../traits.hpp" +namespace nana +{ + /// \brief Draw pictures on a widget by specifying a drawing method that will be employed everytime the widget refreshes. + /// By the end of drawing, the picture may not be displayed immediately. + /// If a picture need to be displayed immediately call nana::gui::API::refresh_window() . + class drawing + :private nana::noncopyable + { + public: + typedef struct{}* diehard_t; ///< A handle to a drawing method + typedef std::function draw_fn_t; ///< A function to draw + + drawing(window w); ///< Create a drawing object for a widget w + + virtual ~drawing(); ///< Just for polymorphism + + bool empty() const; ///< Returns true if the drawing object is invalid. + void update() const; + + void draw(const draw_fn_t&); ///< Draws things that are defined by draw_fn_t. + void draw(draw_fn_t&&); ///< Draws things that are defined by draw_fn_t. + + /// Draws things that are defined by draw_fn_t but will not be deleted when clear() is called. + diehard_t draw_diehard(const draw_fn_t&); + /// Draws things that are defined by draw_fn_t but will not be deleted when clear() is called. + diehard_t draw_diehard(draw_fn_t&&); + void erase(diehard_t); ///< Erases a diehard drawing method. + + void clear(); ///< Erases all. + private: + window handle_; + };//end class drawing +}//end namespace nana +#endif diff --git a/include/nana/gui/effects.hpp b/include/nana/gui/effects.hpp new file mode 100644 index 00000000..dcc31db0 --- /dev/null +++ b/include/nana/gui/effects.hpp @@ -0,0 +1,67 @@ +/* + * Background Effects Implementation + * Copyright(C) 2003-2013 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/gui/effects.hpp + * + */ +#ifndef NANA_GUI_EFFECTS_HPP +#define NANA_GUI_EFFECTS_HPP +#include +#include + +namespace nana +{ + namespace effects + { + enum class edge_nimbus + { + none, active = 0x1, over = 0x2 + }; + + class bground_interface + { + public: + typedef paint::graphics & graph_reference; + + virtual ~bground_interface() = 0; + virtual void take_effect(window, graph_reference) const = 0; + }; + + class bground_factory_interface + { + friend class effects_accessor; + public: + virtual ~bground_factory_interface() = 0; + private: + virtual bground_interface * create() const = 0; + }; + + class bground_transparent + : public bground_factory_interface + { + public: + bground_transparent(std::size_t percent); + private: + virtual bground_interface* create() const; + private: + std::size_t percent_; + }; + + class bground_blur + : public bground_factory_interface + { + public: + bground_blur(std::size_t radius); + private: + virtual bground_interface * create() const; + private: + std::size_t radius_; + }; + } +}//end namespace nana +#endif diff --git a/include/nana/gui/element.hpp b/include/nana/gui/element.hpp new file mode 100644 index 00000000..121e7ce6 --- /dev/null +++ b/include/nana/gui/element.hpp @@ -0,0 +1,194 @@ +/* + * Elements of GUI Gadgets + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/element.hpp + */ +#ifndef NANA_GUI_ELEMENT_HPP +#define NANA_GUI_ELEMENT_HPP + +#include +#include +#include +#include + +namespace nana +{ + namespace paint + { + //forward declaration + class image; + } + + namespace element + { + class element_interface + { + public: + typedef paint::graphics & graph_reference; + + virtual ~element_interface() + {} + + virtual bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state) = 0; + }; + + class crook_interface + { + public: + typedef paint::graphics & graph_reference; + typedef checkstate state; + + struct data + { + state check_state; + bool radio; + }; + + virtual ~crook_interface() + {} + + virtual bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state, const data&) = 0; + }; + + class provider + { + public: + template + struct factory_interface + { + virtual ~factory_interface(){} + virtual ElementInterface* create() const = 0; + virtual void destroy(ElementInterface*) const = 0; + }; + + template + class factory + : public factory_interface + { + public: + typedef factory_interface interface_type; + + ElementInterface * create() const override + { + return (new Element); + } + + void destroy(ElementInterface * p) const override + { + delete p; + } + }; + + void add_crook(const std::string& name, const pat::cloneable>&); + crook_interface* const * keeper_crook(const std::string& name); + }; + + template + void add_crook(const std::string& name) + { + typedef provider::factory factory_t; + provider().add_crook(name, pat::cloneable(factory_t())); + } + + class crook; + }//end namespace element + + template class facade; + + template<> + class facade + : public element::element_interface + { + public: + typedef ::nana::paint::graphics & graph_reference; + typedef element::crook_interface::state state; + + facade(); + facade(const char* name); + + facade & reverse(); + facade & check(state); + state checked() const; + + facade& radio(bool); + bool radio() const; + + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state) override; + private: + element::crook_interface::data data_; + element::crook_interface* const * keeper_; + }; + + namespace element + { + void set_bground(const char* name, const pat::cloneable&); + void set_bground(const char* name, pat::cloneable &&); + + class cite_bground + { + public: + typedef paint::graphics& graph_reference; + typedef pat::cloneable cloneable_element; + + cite_bground(const char*); + + void set(const cloneable_element&); + void set(const char*); + + bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state); + private: + cloneable_element holder_; + element_interface * place_ptr_; + element_interface * const * ref_ptr_; + }; + + class bground + : public element_interface + { + public: + typedef paint::graphics& graph_reference; + + bground(); + bground(const bground&); + ~bground(); + bground& operator=(const bground&); + + bground& image(const paint::image&, bool vertical, const nana::rectangle& valid_area); ///< Set a picture for the background + bground& image(const paint::graphics&, bool vertical, const nana::rectangle& valid_area); ///< Set a picture for the background + + void states(const std::vector &); ///< Set the state sequence of the background picture. + void states(std::vector &&); ///< Set the state sequence of the background picture. + void reset_states(); + + void join(element_state target, element_state joiner); + + void stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom); + + //Implement the methods of element_interface. + virtual bool draw(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle&, element_state); + private: + struct draw_method; + struct draw_image; + struct draw_graph; + + draw_method * method_; + bool vertical_; + nana::rectangle valid_area_; + std::vector states_; + std::map join_; + bool stretch_all_; + unsigned left_, top_, right_, bottom_; + }; //end class bground + }//end namespace element +}//end namespace nana + +#endif //NANA_GUI_ELEMENT_HPP diff --git a/include/nana/gui/filebox.hpp b/include/nana/gui/filebox.hpp new file mode 100644 index 00000000..7dcbb225 --- /dev/null +++ b/include/nana/gui/filebox.hpp @@ -0,0 +1,60 @@ +#ifndef NANA_GUI_FILEBOX_HPP +#define NANA_GUI_FILEBOX_HPP +#include + +namespace nana +{ /// Create an Open or Save dialog box to let user select the name of a file. + class filebox + : nana::noncopyable + { + struct implement; + public: + typedef std::vector> filters; + + filebox(window owner, bool is_open_mode); + ~filebox(); + + /** @brief specify a title for the dialog + * @param string a text for title + */ + nana::string title( nana::string new_title); ///< . Set a new title for the dialog and \return the old title + + /** @brief specify a suggestion directory + * @param string a path of initial directory + * @note the behavior of init_path is different between Win7 and Win2K/XP/Vista, but its behavior under Linux is conformed with Win7. + */ + filebox& init_path(const nana::string&); ///< Suggested init path used to locate a directory when the filebox starts. + filebox& init_file(const nana::string&); ///< Init file, if it contains a path, the init path is replaced by the path of init file. + /// \brief Add a filetype filter. + /// To specify multiple filter in a single description, use a semicolon to separate the patterns(for example,"*.TXT;*.DOC;*.BAK"). + filebox& add_filter(const nana::string& description, ///< for example. "Text File" + const nana::string& filetype ///< filter pattern(for example, "*.TXT") + ); + + filebox& add_filter(const filters &ftres) + { + for (auto &f : ftres) + add_filter(f.first, f.second); + return *this; + }; + + + nana::string path() const; + nana::string file() const; + + /** @brief Display the filebox dialog + */ + bool show() const; + + /** @brief Display the filebox dialog + * @note A function object method alternative to show() + */ + bool operator()() const + { + return show(); + } + private: + implement * impl_; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/layout_utility.hpp b/include/nana/gui/layout_utility.hpp new file mode 100644 index 00000000..a963bbca --- /dev/null +++ b/include/nana/gui/layout_utility.hpp @@ -0,0 +1,43 @@ +/* + * Utility Implementation + * Copyright(C) 2003-2013 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/gui/layout_utility.hpp + * + * + */ + +#ifndef NANA_GUI_LAYOUT_UTILITY_HPP +#define NANA_GUI_LAYOUT_UTILITY_HPP + +#include "basis.hpp" + +namespace nana +{ + //overlap test if overlaped between r1 and r2 + bool overlap(const rectangle& r1, const rectangle& r2); + + // overlap, compute the overlap area between r1 and r2. the r is for root + bool overlap(const rectangle& r1, const rectangle& r2, rectangle& r); + + bool overlap(const rectangle& ir, const size& valid_input_area, const rectangle & dr, const size& valid_dst_area, rectangle& output_src_r, rectangle& output_dst_r); + + bool intersection(const rectangle & r, point pos_beg, point pos_end, point& good_pos_beg, point& good_pos_end); + + /// Zoom the input_s to fit for ref_s + void fit_zoom(const size& input_s, const size& ref_s, size& result_s); + + //zoom + //@brief: Calculate the scaled rectangle by refer dst rectangle, that scale factor is same as that between scaled and refer. + void zoom(const rectangle& refer, const rectangle& scaled, const rectangle& refer_dst, rectangle& r); + + //covered + //@brief: Tests a rectangle whether it is wholly covered by another. + bool covered(const rectangle& underlying, //Rectangle 1 is must under rectangle 2 + const rectangle& cover); +}//end namespace nana +#endif diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp new file mode 100644 index 00000000..f179c556 --- /dev/null +++ b/include/nana/gui/msgbox.hpp @@ -0,0 +1,96 @@ +/* +* A Message Box Class +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2013 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/gui/msgbox.hpp +*/ + +#ifndef NANA_GUI_MSGBOX_HPP +#define NANA_GUI_MSGBOX_HPP + +#include +#include + +namespace nana +{ + /// Prefabricated modal dialog box (with text, icon and actions buttons) that inform and instruct the user. + class msgbox + { + public: + /// Identifiers of icons. + enum icon_t{icon_none, icon_information, icon_warning, icon_error, icon_question}; + + /// Identifiers of buttons. + enum button_t{ok, yes_no, yes_no_cancel}; + + /// Identifiers of buttons that a user clicked. + enum pick_t{pick_ok, pick_yes, pick_no, pick_cancel}; + + /// Default construct that creates a message box with default title and default button, the default button is OK. + msgbox(); + + /// Copy construct from an existing msgbox object. + msgbox(const msgbox&); + + /// Assign from an existing msgbox object. + msgbox& operator=(const msgbox&); + + /// Construct that creates a message box with a specified title and default button. + msgbox(const nana::string&); + + /// Construct that creates a message box with an owner window and a specified title. + msgbox(window, const nana::string&); + + /// Construct that creates a message box with an owner windoow, a specified title and buttons. + msgbox(window, const nana::string&, button_t); + + /// Sets an icon for informing user. + msgbox& icon(icon_t); + + /// Clears the text message buffer. + void clear(); + + /// Writes a string to the buffer. + msgbox & operator<<(const nana::string&); + + /// Writes a string to the buffer. + msgbox & operator<<(const nana::char_t*); + + /// Writes a string to the buffer. + msgbox & operator<<(const nana::charset&); + + // Calls a manipulator to the stream. + msgbox & operator<<(std::ostream& (*)(std::ostream&)); + + /// Write a streamizable object to the buffer. + template + msgbox & operator<<(const T& t) + { + sstream_< +#include + +namespace nana +{ + class notifier; + + struct arg_notifier + { + event_code evt_code; + notifier* notifier_ptr; + nana::point pos; + bool left_button; + bool mid_button; + bool right_button; + + operator arg_mouse() const; + }; + + namespace detail + { + struct notifier_events + { + basic_event mouse_move; + basic_event mouse_down; + basic_event mouse_up; + basic_event mouse_leave; + basic_event dbl_click; + }; + } + + class notifier + { + struct implement; + notifier(const notifier&) = delete; + notifier(notifier&&) = delete; + notifier& operator=(const notifier&) = delete; + notifier& operator=(notifier&&) = delete; + public: + notifier(window); + ~notifier(); + void close(); + void text(const nana::string&); + void icon(const nana::string& icon_file); + void insert_icon(const nana::string& icon_file); + void period(unsigned millisecond); + detail::notifier_events& events(); + window handle() const; + private: + implement * impl_; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp new file mode 100644 index 00000000..1459ba56 --- /dev/null +++ b/include/nana/gui/place.hpp @@ -0,0 +1,130 @@ +/* + * An Implementation of Place for Layout + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/place.cpp + * + * @contributions: + * min/max and splitter bar initial weight by qPCR4vir. + */ + +#ifndef NANA_GUI_PLACE_HPP +#define NANA_GUI_PLACE_HPP +#include +#include +#include +#include + +namespace nana +{ + class widget; + namespace detail + { + class place_agent + { + public: + virtual ~place_agent() = default; + virtual std::unique_ptr create(nana::window) const = 0; + }; + } + + template + class agent + : public detail::place_agent + { + public: + agent(std::function initializer) + : init_(std::move(initializer)) + {} + + agent(const nana::char_t* text) + : text_(text) + {} + + agent(nana::string text, std::function initializer = {}) + : text_(std::move(text)), init_(std::move(initializer)) + {} + + private: + std::unique_ptr create(nana::window handle) const override + { + std::unique_ptr ptr(new Widget(handle)); + ptr->caption(text_); + if (init_) + init_(*ptr); + return std::move(ptr); + } + private: + nana::string text_; + std::function init_; + }; + + /// Layout managment - an object of class place is attached to a widget, and it automatically positions and resizes the children widgets. + class place + : ::nana::noncopyable + { + struct implement; + + class field_interface + { + field_interface(const field_interface&) = delete; + field_interface& operator=(const field_interface&) = delete; + field_interface(field_interface&&) = delete; + field_interface& operator=(field_interface&&) = delete; + public: + field_interface() = default; + virtual ~field_interface() = default; + virtual field_interface& operator<<(const nana::char_t* label) = 0; + virtual field_interface& operator<<(nana::string label) = 0; + virtual field_interface& operator<<(window) = 0; + virtual field_interface& fasten(window) = 0; + + template + field_interface& operator<<(const agent& ag) + { + _m_add_agent(ag); + return *this; + } + private: + virtual void _m_add_agent(const detail::place_agent&) = 0; + }; + public: + /// reference to a field manipulator which refers to a field object created by place + typedef field_interface & field_reference; + + place(); + place(window);///< Attaches to a specified widget. + ~place(); + + /** @brief Bind to a window + * @param handle A handle to a window which the place wants to attach. + * @remark It will throw an exception if the place has already binded to a window. + */ + void bind(window handle); + window window_handle() const; + + void div(const char* s); ///< Divides the attached widget into fields. + field_reference field(const char* name);///< Returns a field with the specified name. + + void field_visible(const char* filed_name, bool visible); ///< +#include GUI_BEDROCK_HPP +#include "effects.hpp" +#include "detail/general_events.hpp" +#include +#include + +namespace nana +{ + class drawer_trigger; + class widget; + +namespace API +{ + void effects_edge_nimbus(window, effects::edge_nimbus); + effects::edge_nimbus effects_edge_nimbus(window); + + void effects_bground(window, const effects::bground_factory_interface&, double fade_rate); + bground_mode effects_bground_mode(window); + void effects_bground_remove(window); + + //namespace dev + //@brief: The interfaces defined in namespace dev are used for developing the nana.gui + namespace dev + { + template + void attach_signal(window wd, Object& object, void (Concept::*f)(::nana::detail::signals::code, const ::nana::detail::signals&)) + { + using namespace ::nana::detail; + bedrock::instance().wd_manager.attach_signal(reinterpret_cast(wd), object, f); + } + + bool set_events(window, const std::shared_ptr&); + + void attach_drawer(widget&, drawer_trigger&); + nana::string window_caption(window); + void window_caption(window, nana::string); + + window create_window(window, bool nested, const rectangle&, const appearance&, widget* attached); + window create_widget(window, const rectangle&, widget* attached); + window create_lite_widget(window, const rectangle&, widget* attached); + window create_frame(window, const rectangle&, widget* attached); + + paint::graphics* window_graphics(window); + }//end namespace dev + + + namespace detail + { + general_events* get_general_events(window); + }//end namespace detail + + void exit(); + + nana::string transform_shortkey_text(nana::string text, nana::string::value_type &shortkey, nana::string::size_type *skpos); + bool register_shortkey(window, unsigned long); + void unregister_shortkey(window); + + nana::size screen_size(); + rectangle screen_area_from_point(const point&); + nana::point cursor_position(); + rectangle make_center(unsigned width, unsigned height); ///< Retrieves a rectangle which is in the center of the screen. + rectangle make_center(window, unsigned width, unsigned height); ///< Retrieves a rectangle which is in the center of the window + + template + void enum_widgets(window wd, bool recursive, EnumFunction && ef) + { + static_assert(std::is_convertible::value, "enum_widgets: The specified Widget is not a widget type."); + + typedef ::nana::detail::basic_window core_window_t; + auto & brock = ::nana::detail::bedrock::instance(); + internal_scope_guard lock; + + auto children = brock.wd_manager.get_children(reinterpret_cast(wd)); + for (auto child : children) + { + auto wgt = dynamic_cast(brock.wd_manager.get_widget(child)); + if (nullptr == wgt) + continue; + + ef(*wgt); + if (recursive) + enum_widgets(wd, recursive, std::forward(ef)); + } + } + + void window_icon_default(const paint::image&); + void window_icon(window, const paint::image&); + bool empty_window(window); ///< Determines whether a window is existing. + void enable_dropfiles(window, bool); + + /// \brief Retrieves the native window of a Nana.GUI window. + /// + /// The native window type is platform-dependent. Under Microsoft Windows, a conversion can be employed between + /// nana::native_window_type and HWND through reinterpret_cast operator. Under X System, a conversion can + /// be employed between nana::native_window_type and Window through reinterpret_cast operator. + /// \return If the function succeeds, the return value is the native window handle to the Nana.GUI window. If fails return zero. + native_window_type root(window); + window root(native_window_type); ///< Retrieves the native window of a Nana.GUI window. + + void fullscreen(window, bool); + bool enabled_double_click(window, bool); + bool insert_frame(window frame, native_window_type); + native_window_type frame_container(window frame); + native_window_type frame_element(window frame, unsigned index); + void close_window(window); + void show_window(window, bool show); ///< Sets a window visible state. + void restore_window(window); + void zoom_window(window, bool ask_for_max); + bool visible(window); + window get_parent_window(window); + window get_owner_window(window); + bool set_parent_window(window, window new_parent); + + template + typename ::nana::dev::event_mapping::type & events(window wd) + { + typedef typename ::nana::dev::event_mapping::type event_type; + + internal_scope_guard lock; + auto * general_evt = detail::get_general_events(wd); + if (nullptr == general_evt) + throw std::invalid_argument("API::events(): bad parameter window handle, no events object or invalid window handle."); + + if (std::is_same::value) + return *static_cast(general_evt); + + auto * widget_evt = dynamic_cast(general_evt); + if (nullptr == widget_evt) + throw std::invalid_argument("API::events(): bad template parameter Widget, the widget type and window handle do not match."); + return *widget_evt; + } + + template::value>::type* = nullptr> + bool emit_event(event_code evt_code, window wd, const EventArg& arg) + { + auto & brock = ::nana::detail::bedrock::instance(); + return brock.emit(evt_code, reinterpret_cast< ::nana::detail::bedrock::core_window_t*>(wd), arg, true, brock.get_thread_context()); + } + + void umake_event(event_handle); + + nana::point window_position(window); + void move_window(window, int x, int y); + void move_window(window wd, const rectangle&); + + void bring_to_top(window); + bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after); + + nana::size window_size(window); + void window_size(window, const size&); + bool window_rectangle(window, rectangle&); + bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. + void window_enabled(window, bool); + bool window_enabled(window); + + /** @brief A widget drawer draws the widget surface in answering an event. + * + * This function will tell the drawer to copy the graphics into window after event answering. + * Tells Nana.GUI to copy the buffer of event window to screen after the event is processed. + * This function only works for a drawer_trigger, when a drawer_trigger receives an event, + * after drawing, a drawer_trigger should call lazy_refresh to tell the Nana.GUI to refresh + * the window to the screen after the event process finished. + */ + void lazy_refresh(); + + /** @brief: calls refresh() of a widget's drawer. if currently state is lazy_refresh, Nana.GUI may paste the drawing on the window after an event processing. + * @param window: specify a window to be refreshed. + */ + void refresh_window(window); ///< Refreshs the window and display it immediately calling the refresh method of its drawer_trigger.. + void refresh_window_tree(window); ///< Refreshs the specified window and all its children windows, then display it immediately + void update_window(window); ///< Copies the off-screen buffer to the screen for immediate display. + + void window_caption(window, const nana::string& title); + nana::string window_caption(window); + + void window_cursor(window, cursor); + cursor window_cursor(window); + + void activate_window(window); + bool is_focus_window(window); + window focus_window(); + void focus_window(window); + + window capture_window(); + window capture_window(window, bool); ///< Enables or disables the window to grab the mouse input + void capture_ignore_children(bool ignore); ///< Enables or disables the captured window whether redirects the mouse input to its children if the mouse is over its children. + void modal_window(window); ///< Blocks the routine til the specified window is closed. + void wait_for(window); + color_t foreground(window); + color_t foreground(window, color_t); + color_t background(window); + color_t background(window, color_t); + color_t active(window); + color_t active(window, color_t); + + void create_caret(window, unsigned width, unsigned height); + void destroy_caret(window); + void caret_effective_range(window, const rectangle&); + void caret_pos(window, int x, int y); + nana::point caret_pos(window); + nana::size caret_size(window); + void caret_size(window, const size&); + void caret_visible(window, bool is_show); + bool caret_visible(window); + + void tabstop(window); ///< Sets the window that owns the tabstop. + /// treu: The focus is not to be changed when Tab key is pressed, and a key_char event with tab will be generated. + void eat_tabstop(window, bool); + window move_tabstop(window, bool next); ///< Sets the focus to the window which tabstop is near to the specified window. + + bool glass_window(window); /// \deprecated + bool glass_window(window, bool); /// \deprecated + + /// Sets the window active state. If a window active state is false, the window will not obtain the focus when a mouse clicks on it wich will be obteined by take_if_has_active_false. + void take_active(window, bool has_active, window take_if_has_active_false); + + bool window_graphics(window, nana::paint::graphics&); + bool root_graphics(window, nana::paint::graphics&); + bool get_visual_rectangle(window, nana::rectangle&); + + void typeface(window, const nana::paint::font&); + paint::font typeface(window); + + bool calc_screen_point(window, point&); /// +namespace nana +{ + class state_cursor + { + state_cursor(const state_cursor&) = delete; + state_cursor& operator=(const state_cursor&) = delete; + public: + state_cursor(window, cursor); + state_cursor(state_cursor&&); + state_cursor& operator=(state_cursor&&); + ~state_cursor(); + private: + window handle_; + }; +} \ No newline at end of file diff --git a/include/nana/gui/timer.hpp b/include/nana/gui/timer.hpp new file mode 100644 index 00000000..458e929e --- /dev/null +++ b/include/nana/gui/timer.hpp @@ -0,0 +1,60 @@ +/* + * A Timer Implementation + * Copyright(C) 2003-2013 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/gui/timer.hpp + * @description: + * A timer can repeatedly call a piece of code. The duration between + * calls is specified in milliseconds. Timer is defferent from other graphics + * controls, it has no graphics interface. + */ + +#ifndef NANA_GUI_TIMER_HPP +#define NANA_GUI_TIMER_HPP +#include + +namespace nana +{ + /// Can repeatedly call a piece of code. + + struct arg_elapse + { + long long id; //timer identifier; + }; + + class timer + { + struct implement; + + timer(const timer&) = delete; + timer& operator=(const timer&) = delete; + timer(timer&&) = delete; + timer& operator=(timer&&) = delete; + public: + timer(); + + ~timer(); + + template + void elapse(Function && fn) + { + elapse_.connect(std::forward(fn)); + } + + void reset(); + void start(); + bool started() const; + void stop(); + + void interval(unsigned milliseconds); ///< Set the duration between calls (millisec ??) + unsigned interval() const; + private: + nana::basic_event elapse_; + implement * const impl_; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/tooltip.hpp b/include/nana/gui/tooltip.hpp new file mode 100644 index 00000000..cbe29d0d --- /dev/null +++ b/include/nana/gui/tooltip.hpp @@ -0,0 +1,76 @@ +/* + * A Tooltip Implementation + * Copyright(C) 2003-2013 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/gui/widgets/tooltip.hpp + */ + +#ifndef NANA_GUI_WIDGETS_TOOLTIP_HPP +#define NANA_GUI_WIDGETS_TOOLTIP_HPP +#include "widgets/widget.hpp" + +namespace nana +{ + ///tooltip_interface + ///An interface for user-defined tooltip window. + class tooltip_interface + { + public: + virtual ~tooltip_interface(){} + + virtual bool tooltip_empty() const = 0; + virtual nana::size tooltip_size() const = 0; + virtual void tooltip_text(const nana::string&) = 0; + virtual void tooltip_move(const nana::point& screen_pos, bool ignore_pos) = 0; + virtual void duration(std::size_t) = 0; + }; + + class tooltip + { + class factory_interface + { + public: + virtual ~factory_interface(){} + virtual tooltip_interface* create() = 0; + virtual void destroy(tooltip_interface*) = 0; + }; + + template + class factory + : public factory_interface + { + tooltip_interface * create() override + { + return new TooltipWindow; + } + + void destroy(tooltip_interface* p) override + { + delete p; + } + }; + public: + typedef factory_interface factory_if_type; + + template + static void make_factory() + { + _m_hold_factory(new factory); + } + + tooltip(){} + tooltip(window w, const nana::string &tip){set(w,tip);} + + + static void set(window, const nana::string&); + static void show(window, point pos, const nana::string&, std::size_t duration); + static void close(); + private: + static void _m_hold_factory(factory_interface*); + };//class tooltip +}//namespace nana +#endif diff --git a/include/nana/gui/widgets/button.hpp b/include/nana/gui/widgets/button.hpp new file mode 100644 index 00000000..f6d67d9b --- /dev/null +++ b/include/nana/gui/widgets/button.hpp @@ -0,0 +1,113 @@ +/* + * A Button Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/button.hpp + */ + +#ifndef NANA_GUI_WIDGET_BUTTON_HPP +#define NANA_GUI_WIDGET_BUTTON_HPP +#include "widget.hpp" +#include + + +namespace nana{ + namespace drawerbase + { + namespace button + { + /// Draw the button + class trigger: public drawer_trigger + { + public: + trigger(); + ~trigger(); + + void emit_click(); + void icon(const nana::paint::image&); + bool enable_pushed(bool); + bool pushed(bool); + bool pushed() const; + void omitted(bool); + bool focus_color(bool); + + element::cite_bground & cite(); + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void key_char(graph_reference, const arg_keyboard&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void focus(graph_reference, const arg_focus&) override; + private: + void _m_draw(graph_reference); + void _m_draw_title(graph_reference, bool enabled); + void _m_draw_background(graph_reference); + void _m_draw_border(graph_reference); + private: + widget* widget_; + paint::graphics* graph_; + + element::cite_bground cite_; + + struct attr_tag + { + element_state e_state; + bool omitted; + bool focused; + bool pushed; + bool keep_pressed; + bool enable_pushed; + bool focus_color; + paint::image * icon; + color_t bgcolor; + color_t fgcolor; + }attr_; + }; + }//end namespace button + }//end namespace drawerbase + + /// Define a button widget and provides the interfaces to be operational + class button + : public widget_object + { + typedef widget_object base_type; + public: + button(); + button(window, bool visible); + button(window, const nana::string& caption, bool visible = true); + button(window, const nana::char_t* caption, bool visible = true); + button(window, const nana::rectangle& = rectangle(), bool visible = true); + + button& icon(const nana::paint::image&); + button& enable_pushed(bool); + bool pushed() const; + button& pushed(bool); + button& omitted(bool); ///< Enables/Disables omitting displaying the caption if the text is too long. + button& enable_focus_color(bool); ///< Enables/Disables showing the caption with a special color to indicate the button is focused. + + button& set_bground(const pat::cloneable&); ///< Sets a user-defined background element. + button& set_bground(const std::string&); ///< Sets a pre-defined background element by a name. + + button& transparent(bool enable); + bool transparent() const; + + button& edge_effects(bool enable); + private: + void _m_shortkey(); + private: + //Overrides widget virtual functions + void _m_complete_creation() override; + void _m_caption(nana::string&&) override; + }; +}//end namespace nana +#endif + diff --git a/include/nana/gui/widgets/categorize.hpp b/include/nana/gui/widgets/categorize.hpp new file mode 100644 index 00000000..204e4fc5 --- /dev/null +++ b/include/nana/gui/widgets/categorize.hpp @@ -0,0 +1,247 @@ +/* + * A Categorize Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/categorize.hpp + */ + +#ifndef NANA_GUI_WIDGET_CATEGORIZE_HPP +#define NANA_GUI_WIDGET_CATEGORIZE_HPP + +#include +#include +#include + +namespace nana +{ + template class categorize; + + template + struct arg_categorize + { + categorize & widget; + ValueType & value; + + arg_categorize(categorize & wdg, ValueType& v) + : widget(wdg), value(v) + {} + }; + + namespace drawerbase + { + namespace categorize + { + template + struct categorize_events + : public general_events + { + basic_event> selected; + }; + + class event_agent_interface + { + public: + virtual ~event_agent_interface(){} + virtual void selected(::nana::any&) = 0; + }; + + template + class event_agent + : public event_agent_interface + { + public: + event_agent(::nana::categorize& wdg) + : widget_(wdg) + {} + + void selected(::nana::any & var) + { + auto vp = var.get(); + + T null_val; + arg_categorize arg(widget_, vp ? *vp : null_val); + widget_.events().selected.emit(arg); + } + private: + ::nana::categorize & widget_; + }; + + class renderer + { + public: + typedef nana::paint::graphics & graph_reference; + + struct ui_element + { + enum t + { + none, //Out of the widget + somewhere, item_root, item_name, item_arrow + }; + + t what; + std::size_t index; + + ui_element(); + }; + + virtual ~renderer() = 0; + virtual void background(graph_reference, window wd, const nana::rectangle&, const ui_element&) = 0; + virtual void root_arrow(graph_reference, const nana::rectangle&, mouse_action) = 0; + virtual void item(graph_reference, const nana::rectangle&, std::size_t index, const nana::string& name, unsigned textheight, bool has_child, mouse_action) = 0; + virtual void border(graph_reference) = 0; + }; + + class trigger + : public drawer_trigger + { + class scheme; + public: + typedef renderer::ui_element ui_element; + + trigger(); + ~trigger(); + + void insert(const nana::string&, nana::any); + bool childset(const nana::string&, nana::any); + bool childset_erase(const nana::string&); + bool clear(); + + //splitstr + //@brief: Sets the splitstr. If the parameter will be ingored if it is an empty string. + void splitstr(const nana::string&); + const nana::string& splitstr() const; + + void path(const nana::string&); + nana::string path() const; + + template + void create_event_agent(::nana::categorize& wdg) + { + event_agent_.reset(new event_agent(wdg)); + _m_event_agent_ready(); + } + + nana::any & value() const; + private: + void _m_event_agent_ready() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + private: + std::unique_ptr event_agent_; + scheme * scheme_; + }; + }//end namespace categorize + }//end namespace drawerbase + + + + /// \brief Represent an architecture of categories and what category is chosen. + /// The categorize widget can be used for representing a path of a directory or the order of a hierarchy. + template + class categorize + : public widget_object> + { + public: + typedef T value_type; ///< The type of objects stored + typedef drawerbase::categorize::renderer renderer; ///< The interface for user-defined renderer. + + categorize() + { + this->get_drawer_trigger().create_event_agent(*this); + } + + categorize(window wd, const rectangle& r = rectangle(), bool visible = true) + { + this->get_drawer_trigger().template create_event_agent(*this); + this->create(wd, r, visible); + } + + categorize(window wd, bool visible) + : categorize(wd, ::nana::rectangle(), visible) + { + } + + categorize(window wd, const nana::string& text, bool visible = true) + : categorize(wd, ::nana::rectangle(), visible) + { + this->caption(text); + } + + categorize(window wd, const nana::char_t* text, bool visible = true) + : categorize(wd, ::nana::rectangle(), visible) + { + this->caption(text); + } + + /// Insert a new category with a specified name and the object of value type. + /// The new category would be inserted as a child in current category, + /// and after inserting, the new category is replaced of the current category as a new current one. + categorize& insert(const nana::string& name, const value_type& value) + { + this->get_drawer_trigger().insert(name, value); + API::update_window(*this); + return *this; + } + + /// Inserts a child category into current category. + categorize& childset(const nana::string& name, const value_type& value) + { + if(this->get_drawer_trigger().childset(name, value)) + API::update_window(*this); + return *this; + } + + /// Erases a child category with a specified name from current category. + categorize& childset_erase(const nana::string& name) + { + if(this->get_drawer_trigger().childset_erase(name)) + API::update_window(*this); + return *this; + } + + void clear() + { + if(this->get_drawer_trigger().clear()) + API::update_window(*this); + } + + /// Sets the splitter string + categorize& splitstr(const nana::string& sstr) + { + this->get_drawer_trigger().splitstr(sstr); + return *this; + } + + nana::string splitstr() const + { + return this->get_drawer_trigger().splitstr(); + } + + /// Retrieves a reference of the current category's value type object. If current category is empty, it throws a exception of std::runtime_error. + value_type& value() const + { + return this->get_drawer_trigger().value(); + } + private: + //Overrides widget's virtual functions + void _m_caption(nana::string&& str) override + { + this->get_drawer_trigger().path(str); + API::dev::window_caption(*this, this->get_drawer_trigger().path()); + } + }; +}//end namespace nana + +#endif diff --git a/include/nana/gui/widgets/checkbox.hpp b/include/nana/gui/widgets/checkbox.hpp new file mode 100644 index 00000000..5f9da66a --- /dev/null +++ b/include/nana/gui/widgets/checkbox.hpp @@ -0,0 +1,100 @@ +/* + * A CheckBox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/checkbox.hpp + */ + +#ifndef NANA_GUI_WIDGET_CHECKBOX_HPP +#define NANA_GUI_WIDGET_CHECKBOX_HPP +#include "widget.hpp" +#include +#include + +namespace nana { +namespace drawerbase +{ + namespace checkbox + { + class drawer + : public drawer_trigger + { + struct implement; + public: + drawer(); + ~drawer(); //To instance imptr_; + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + public: + implement * impl() const; + private: + void _m_draw(graph_reference); + void _m_draw_background(graph_reference); + void _m_draw_checkbox(graph_reference, unsigned first_line_height); + void _m_draw_title(graph_reference); + private: + static const int interval = 4; + widget* widget_; + unsigned state_; + std::unique_ptr imptr_; + implement * impl_; + }; + }//end namespace checkbox +}//end namespace drawerbase + + + class checkbox + : public widget_object + { + public: + checkbox(); + checkbox(window, bool visible); + checkbox(window, const nana::string& text, bool visible = true); + checkbox(window, const nana::char_t* text, bool visible = true); + checkbox(window, const rectangle& = rectangle(), bool visible = true); + + void element_set(const char* name); + void react(bool want); ///< Enables the reverse check while clicking on the checkbox. + bool checked() const; + void check(bool chk); + + /// \brief With the radio mode, users make a choice among a set of mutually exclusive, + /// related options. Users can choose one and only one option. + /// There is a helper class manages checkboxs for radio mode, + /// \see radio_group. + void radio(bool); + void transparent(bool value); + bool transparent() const; + };//end class checkbox + /// for managing checkboxs in radio mode + class radio_group + { + struct element_tag + { + checkbox * uiobj; + event_handle eh_checked; + event_handle eh_destroy; + }; + public: + ~radio_group(); + void add(checkbox&); + std::size_t checked() const; ///< Retrieves the index of the checkbox which is checked. + std::size_t size() const; + private: + void _m_checked(const arg_mouse&); + void _m_destroy(const arg_destroy&); + private: + std::vector ui_container_; + }; +}//end namespace nana + +#endif diff --git a/include/nana/gui/widgets/combox.hpp b/include/nana/gui/widgets/combox.hpp new file mode 100644 index 00000000..fc00c092 --- /dev/null +++ b/include/nana/gui/widgets/combox.hpp @@ -0,0 +1,233 @@ +/* + * A Combox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/combox.hpp + */ + +#ifndef NANA_GUI_WIDGETS_COMBOX_HPP +#define NANA_GUI_WIDGETS_COMBOX_HPP +#include "widget.hpp" +#include "float_listbox.hpp" +#include +#include +#include + +namespace nana +{ + /// A list box combined with a textbox - the list box should drop down when the user selects the arrow next to the control + class combox; + + struct arg_combox + { + combox & widget; + + arg_combox(combox& wdg) + : widget(wdg) + {} + }; + + namespace drawerbase + { + namespace combox + { + struct combox_events + : public general_events + { + basic_event selected; + }; + + class drawer_impl; + + class trigger + : public drawer_trigger + { + public: + trigger(); + ~trigger(); + + void set_accept(std::function&&); + + drawer_impl& get_drawer_impl(); + const drawer_impl& get_drawer_impl() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void focus(graph_reference, const arg_focus&) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + private: + std::function pred_acceptive_; + drawer_impl * drawer_; + }; + + class item_proxy + : public std::iterator + { + public: + item_proxy(drawer_impl*, std::size_t pos); + item_proxy& text(const nana::string&); + nana::string text() const; + item_proxy& select(); + bool selected() const; + item_proxy& icon(const nana::paint::image&); + nana::paint::image icon() const; + + template + T * value_ptr() const + { + auto p = _m_anyobj(false); + return (p ? p->get() : nullptr); + } + + template + T & value() const + { + auto * pany = _m_anyobj(false); + if (nullptr == pany) + throw std::runtime_error("combox::item_proxy.value() is empty"); + + T * p = pany->get(); + if (nullptr == p) + throw std::runtime_error("combox::item_proxy.value() invalid type of value"); + return *p; + } + + template + item_proxy& value(const T& t) + { + *_m_anyobj(true) = t; + return *this; + } + + template + item_proxy& value(T&& t) + { + *_m_anyobj(true) = std::move(t); + return *this; + } + public: + /// Behavior of Iterator's value_type + bool operator==(const nana::string&) const; + bool operator==(const char*) const; + bool operator==(const wchar_t*) const; + + /// Behavior of Iterator + item_proxy & operator=(const item_proxy&); + + /// Behavior of Iterator + item_proxy & operator++(); + + /// Behavior of Iterator + item_proxy operator++(int); + + /// Behavior of Iterator + item_proxy& operator*(); + + /// Behavior of Iterator + const item_proxy& operator*() const; + + /// Behavior of Iterator + item_proxy* operator->(); + + /// Behavior of Iterator + const item_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const item_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const item_proxy&) const; + private: + nana::any * _m_anyobj(bool alloc_if_empty) const; + private: + drawer_impl * impl_; + std::size_t pos_; + }; + }//end namespace combox + }//end namespace drawerbase + + class combox + : public widget_object, + public nana::concepts::any_objective + { + public: + typedef float_listbox::item_renderer item_renderer; + typedef drawerbase::combox::item_proxy item_proxy; + + combox(); + combox(window, bool visible); + combox(window, const nana::string& text, bool visible = true); + combox(window, const nana::char_t* text, bool visible = true); + combox(window, const rectangle& r = rectangle(), bool visible = true); + + void clear(); + void editable(bool); + bool editable() const; + void set_accept(std::function); + combox& push_back(const nana::string&); + std::size_t the_number_of_options() const; + std::size_t option() const; ///< Index of the last selected, from drop-down list, item. + void option(std::size_t); ///< Select the text specified by index + nana::string text(std::size_t) const; + void erase(std::size_t pos); + + template + item_proxy operator[](const Key& kv) + { + typedef typename nana::detail::type_escape::type key_t; + std::shared_ptr p(new nana::key >(kv), [](nana::detail::key_interface*p) + { + delete p; + }); + + return _m_at_key(std::move(p)); + } + + template + void erase_key(const Key& kv) + { + typedef typename nana::detail::type_escape::type key_t; + std::unique_ptr p(new nana::key >(kv)); + _m_erase(p.get()); + } + + template + void erase_key(Key&& kv) + { + typedef typename nana::detail::type_escape::type key_t; + std::unique_ptr p(new nana::key >(std::move(kv))); + _m_erase(p.get()); + } + + /// \brief Set user-defined item renderer object. + /// It is an address therefore the user should not destroy the renderer object + /// after it is set to the combox. Passing null_ptr cancels the user-defined renderer object. + void renderer(item_renderer*); + + void image(std::size_t, const nana::paint::image&); + nana::paint::image image(std::size_t) const; + void image_pixels(unsigned); ///&&); + void _m_erase(nana::detail::key_interface*); + private: + //Overrides widget's virtual functions + nana::string _m_caption() const override; + void _m_caption(nana::string&&) override; + nana::any * _m_anyobj(std::size_t pos, bool alloc_if_empty) const override; + }; +} +#endif diff --git a/include/nana/gui/widgets/date_chooser.hpp b/include/nana/gui/widgets/date_chooser.hpp new file mode 100644 index 00000000..03b47c5d --- /dev/null +++ b/include/nana/gui/widgets/date_chooser.hpp @@ -0,0 +1,123 @@ +/* + * A date chooser Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/date_chooser.hpp + */ + +#ifndef NANA_GUI_WIDGETS_DATE_CHOOSER_HPP +#define NANA_GUI_WIDGETS_DATE_CHOOSER_HPP + +#include "widget.hpp" +#include + +namespace nana +{ + namespace drawerbase + { + namespace date_chooser + { + class trigger : public drawer_trigger + { + public: + static const int topbar_height = 34; + static const int border_size = 3; + + enum class transform_action{none, to_left, to_right, to_enter, to_leave}; + enum class where{none, left_button, right_button, topbar, textarea}; + enum class page{date, month}; + + struct drawing_basis + { + nana::point refpos; + double line_s; + double row_s; + }; + + trigger(); + bool chose() const; + nana::date read() const; + void week_name(unsigned index, const nana::string&); + void month_name(unsigned index, const nana::string&); + private: + void _m_init_color(); + where _m_pos_where(graph_reference, int x, int y); + void _m_draw(graph_reference); + void _m_draw_topbar(graph_reference); + void _m_make_drawing_basis(drawing_basis&, graph_reference, const nana::point& refpos); + void _m_draw_pos(drawing_basis &, graph_reference, int x, int y, const nana::string&, bool primary, bool sel); + void _m_draw_pos(drawing_basis &, graph_reference, int x, int y, int number, bool primary, bool sel); + void _m_draw_ex_days(drawing_basis &, graph_reference, int begx, int begy, bool before); + void _m_draw_days(const nana::point& refpos, graph_reference); + void _m_draw_months(const nana::point& refpos, graph_reference); + bool _m_get_trace(point, int & res); + void _m_perf_transform(transform_action tfid, graph_reference, graph_reference dirtybuf, graph_reference newbuf, const nana::point& refpos); + private: + void refresh(graph_reference); + void attached(widget_reference, graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + private: + nana::string weekstr_[7]; + nana::string monthstr_[12]; + + widget * widget_; + + bool chose_; + page page_; + where pos_; + nana::point trace_pos_; + + drawing_basis dbasis_; + + struct + { + int year; + int month; + int day; + }chdate_; + + struct + { + int year; + int month; + }chmonth_; + + struct color_tag + { + nana::color_t highlight; + nana::color_t selected; + nana::color_t normal; + nana::color_t bkcolor; + }color_; + }; + + }//end namespace date_chooser + + }//end namespace drawerbase + + /// \see nana::date + class date_chooser + : public widget_object + { + public: + date_chooser(); + date_chooser(window, bool visible); + date_chooser(window, const nana::string& text, bool visible = true); + date_chooser(window, const nana::char_t* text, bool visible = true); + date_chooser(window, const nana::rectangle& r = rectangle(), bool visible = true); + + bool chose() const; + nana::date read() const; + void weekstr(unsigned index, const nana::string&);/// + +namespace nana{ namespace widgets{ namespace detail +{ + /// A component set used for accessing the components of items of a widget. + template + class compset + { + public: + /// A type of widget-defined components. + typedef Component component_t; + + /// A type of widget-defined item attribute. + typedef ItemAttribute item_attribute_t; + + /// A type of a componenet state for rendering. + struct comp_attribute_t + { + nana::rectangle area; + bool mouse_pointed; + }; + + public: + /// The destrcutor + virtual ~compset(){} + + /// Access the widget-defined item attribute. + virtual const item_attribute_t& item_attribute() const = 0; + + /// Access a specified component of the item. + virtual bool comp_attribute(component_t, comp_attribute_t &) const = 0; + }; + + /// A component set placer used for specifying component position and size. + template + class compset_placer + { + public: + typedef ::nana::paint::graphics & graph_reference; + /// A type of widget-defined components. + typedef Component component_t; + + /// A type of widget-defined item attribute. + typedef ItemAttribute item_attribute_t; + public: + /// The destrcutor. + virtual ~compset_placer(){} + + /// Enable/Disable the specified component. + virtual void enable(component_t, bool) = 0; + virtual bool enabled(component_t) const = 0; + + /// Height of an item, in pixels. + // this method is content-indepented, this feature is easy for implementation. + virtual unsigned item_height(graph_reference) const = 0; + + /// Width of an item, in pixels + virtual unsigned item_width(graph_reference, const item_attribute_t&) const = 0; + + /// Locate a component through the specified coordinate. + /// @param comp the component of the item. + /// @param attr the attribute of the item. + /// @param r the pointer refers to a rectangle for receiving the position and size of the component. + /// @returns the true when the component is located by the locator. + virtual bool locate(component_t comp, const item_attribute_t& attr, rectangle * r) const = 0; + }; +}//end namespace detail +}//end namespace widgets +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/detail/tree_cont.hpp b/include/nana/gui/widgets/detail/tree_cont.hpp new file mode 100644 index 00000000..0c5e5423 --- /dev/null +++ b/include/nana/gui/widgets/detail/tree_cont.hpp @@ -0,0 +1,518 @@ +/* + * A Tree Container class implementation + * Copyright(C) 2003-2013 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/gui/widgets/detail/tree_cont.hpp + */ + +#ifndef NANA_GUI_WIDGETS_DETAIL_TREE_CONT_HPP +#define NANA_GUI_WIDGETS_DETAIL_TREE_CONT_HPP +#include + +namespace nana +{ +namespace widgets +{ +namespace detail +{ + template + struct tree_node + { + typedef std::pair value_type; + + value_type value; + + tree_node *owner; + tree_node *next; + tree_node *child; + + tree_node(tree_node* owner) + :owner(owner), next(nullptr), child(nullptr) + {} + + ~tree_node() + { + if(owner) + { + tree_node * t = owner->child; + if(t != this) + { + while(t->next != this) + t = t->next; + t->next = next; + } + else + owner->child = next; + } + + tree_node * t = child; + while(t) + { + tree_node * t_next = t->next; + delete t; + t = t_next; + } + } + }; + + template + class tree_cont + { + typedef tree_cont self_type; + + public: + typedef UserData element_type; + typedef tree_node node_type; + typedef typename node_type::value_type value_type; + + tree_cont() + :root_(nullptr) + {} + + ~tree_cont() + { + clear(); + } + + void clear() + { + remove(root_.child); + } + + bool verify(const node_type* node) const + { + if(node) + { + while(node->owner) + { + if(node->owner == &root_) + return true; + + node = node->owner; + } + } + return false; + } + + node_type* get_root() const + { + return &root_; + } + + node_type* get_owner(const node_type* node) const + { + return (verify(node) && (node->owner != &root_) ? node->owner : nullptr); + } + + node_type * node(node_type* node, const nana::string& key) + { + if(node) + { + for(node_type * child = node->child; child; child = child->next) + { + if(child->value.first == key) + return child; + } + } + return nullptr; + } + + node_type* insert(node_type* node, const nana::string& key, const element_type& elem) + { + if(nullptr == node) + return insert(key, elem); + + if(verify(node)) + { + node_type **new_node_ptr; + if(node->child) + { + node_type* child = node->child; + for(; child; child = child->next) + { + if(child->value.first == key) + { + child->value.second = elem; + return child; + } + } + + child = node->child; + while(child->next) + child = child->next; + + new_node_ptr = &(child->next); + } + else + new_node_ptr = &(node->child); + + *new_node_ptr = new node_type(node); + + (*new_node_ptr)->value.first = key; + (*new_node_ptr)->value.second = elem; + return (*new_node_ptr); + } + return nullptr; + } + + node_type* insert(const nana::string& key, const element_type& elem) + { + auto node = _m_locate(key); + if(node) + node->value.second = elem; + return node; + } + + void remove(node_type* node) + { + if(verify(node)) + delete node; + } + + node_type* find(const nana::string& path) const + { + return _m_locate(path); + } + + node_type* ref(const nana::string& path) + { + return _m_locate(path); + } + + unsigned indent_size(const node_type* node) const + { + if(node) + { + unsigned indent = 0; + for(;(node = node->owner); ++indent) + { + if(node == &root_) return indent; + } + } + return 0; + } + + template + void for_each(node_type* node, Functor f) + { + if(nullptr == node) node = root_.child; + int state = 0; //0: Sibling, the last is a sibling of node + //1: Owner, the last is the owner of node + //>= 2: Children, the last is is a child of the node that before this node. + while(node) + { + switch(f(*node, state)) + { + case 0: return; + case 1: + { + if(node->child) + { + node = node->child; + state = 1; + } + else + return; + continue; + } + break; + } + + if(node->next) + { + node = node->next; + state = 0; + } + else + { + state = 1; + if(node == &root_) return; + + while(true) + { + ++state; + if(node->owner->next) + { + node = node->owner->next; + break; + } + else + node = node->owner; + + if(node == &root_) return; + } + } + } + } + + template + void for_each(node_type* node, Functor f) const + { + if(nullptr == node) node = root_.child; + int state = 0; //0: Sibling, the last is a sibling of node + //1: Owner, the last is the owner of node + //>= 2: Children, the last is is a child of the node that before this node. + while(node) + { + switch(f(*node, state)) + { + case 0: return; + case 1: + { + if(node->child) + { + node = node->child; + state = 1; + } + else + return; + continue; + } + break; + } + + if(node->next) + { + node = node->next; + state = 0; + } + else + { + state = 1; + if(node == &root_) return; + + while(true) + { + ++state; + if(node->owner->next) + { + node = node->owner->next; + break; + } + else + node = node->owner; + + if(node == &root_) return; + } + } + } + } + + template + unsigned child_size_if(const nana::string& key, PredAllowChild pac) const + { + auto node = _m_locate(key); + return (node ? child_size_if(*node, pac) : 0); + } + + template + unsigned child_size_if(const node_type& node, PredAllowChild pac) const + { + unsigned size = 0; + const node_type* pnode = node.child; + while(pnode) + { + ++size; + if(pnode->child && pac(*pnode)) + size += child_size_if(*pnode, pac); + + pnode = pnode->next; + } + return size; + } + + template + unsigned distance_if(const node_type * node, PredAllowChild pac) const + { + if(nullptr == node) return 0; + const node_type * iterator = root_.child; + + unsigned off = 0; + std::stack stack; + + while(iterator && iterator != node) + { + ++off; + + if(iterator->child && pac(*iterator)) + { + stack.push(iterator); + iterator = iterator->child; + } + else + iterator = iterator->next; + + while((nullptr == iterator) && stack.size()) + { + iterator = stack.top()->next; + stack.pop(); + } + } + return off; + } + + template + node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac) + { + if(nullptr == node) node = root_.child; + + std::stack stack; + + while(node && off) + { + --off; + if(node->child && pac(*node)) + { + stack.push(node); + node = node->child; + } + else + node = node->next; + + while(nullptr == node && stack.size()) + { + node = stack.top(); + stack.pop(); + node = node->next; + } + } + + return node; + } + private: + //Functor defintions + + struct each_make_node + { + each_make_node(self_type& self) + :node(&(self.root_)) + {} + + bool operator()(const nana::string& key_node) + { + node_type *child = node->child; + node_type *tail = nullptr; + while(child) + { + if(key_node == child->value.first) + { + node = child; + return true; + } + tail = child; + child = child->next; + } + + child = new node_type(node); + if(tail) + tail->next = child; + else + node->child = child; + + child->value.first = key_node; + node = child; + return true; + } + + node_type * node; + }; + + + struct find_key_node + { + find_key_node(const self_type& self) + :node(&self.root_) + {} + + bool operator()(const nana::string& key_node) + { + return ((node = _m_find(node->child, key_node)) != nullptr); + } + + node_type *node; + }; + private: + static node_type* _m_find(node_type* node, const nana::string& key_node) + { + while(node) + { + if(key_node == node->value.first) + return node; + + node = node->next; + } + return nullptr; + } + + template + void _m_for_each(const nana::string& key, Function function) const + { + if(key.size()) + { + nana::string::size_type beg = 0; + auto end = key.find_first_of(STR("\\/")); + + while(end != nana::string::npos) + { + if(beg != end) + { + if(function(key.substr(beg, end - beg)) == false) + return; + } + + auto next = key.find_first_not_of(STR("\\/"), end); + if(next != nana::string::npos) + { + beg = next; + end = key.find_first_of(STR("\\/"), beg); + } + else + return; + } + + function(key.substr(beg, key.size() - beg)); + } + } + + template + node_type* _m_locate(const nana::string& key) + { + if(key.size()) + { + if(CreateIfNotExists) + { + each_make_node emn(*this); + _m_for_each(key, emn); + return emn.node; + } + else + { + find_key_node fkn(*this); + _m_for_each(key, fkn); + return const_cast(fkn.node); + } + } + return &root_; + } + + node_type* _m_locate(const nana::string& key) const + { + if(key.size()) + { + find_key_node fkn(*this); + _m_for_each(key, fkn); + return fkn.node; + } + return &root_; + } + private: + mutable node_type root_; + };//end class tree_cont +}//end namespace detail +}//end namespace widgets +}//end namesace nana +#endif diff --git a/include/nana/gui/widgets/float_listbox.hpp b/include/nana/gui/widgets/float_listbox.hpp new file mode 100644 index 00000000..146a220f --- /dev/null +++ b/include/nana/gui/widgets/float_listbox.hpp @@ -0,0 +1,107 @@ +/* + * A float_listbox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/float_listbox.hpp + */ + +#ifndef NANA_GUI_WIDGETS_FLOAT_LISTBOX_HPP +#define NANA_GUI_WIDGETS_FLOAT_LISTBOX_HPP + +#include "widget.hpp" +#include +#include + +namespace nana +{ + namespace drawerbase{ + namespace float_listbox + { + class item_interface + { + public: + virtual ~item_interface(){} + + virtual const nana::paint::image & image() const = 0; + virtual const nana::char_t* text() const = 0; + }; + + //struct module_def + //@brief: This defines a data structure used for float_listbox + struct module_def + { + std::vector> items; + + std::size_t max_items; // the number of items display. + mutable std::size_t index; // the result of the selection. + mutable bool have_selected; + + module_def(); + }; + + class item_renderer + { + public: + typedef widget& widget_reference; + typedef paint::graphics& graph_reference; + enum state_t{StateNone, StateHighlighted}; + + virtual ~item_renderer() = 0; + virtual void image(bool enabled, unsigned pixels) = 0; + virtual void render(widget_reference, graph_reference, const nana::rectangle&, const item_interface*, state_t) = 0; + virtual unsigned item_pixels(graph_reference) const = 0; + }; + + class drawer_impl; + + class trigger + : public drawer_trigger + { + public: + trigger(); + ~trigger(); + drawer_impl& get_drawer_impl(); + const drawer_impl& get_drawer_impl() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + private: + class drawer_impl *drawer_; + }; + } + }//end namespace drawerbase + + class float_listbox + : public widget_object + { + typedef widget_object base_type; + public: + typedef drawerbase::float_listbox::item_renderer item_renderer; + typedef drawerbase::float_listbox::module_def module_type; + typedef drawerbase::float_listbox::item_interface item_interface; + + /** @brief Constructor + * @param window A handle to a window which is a owner of float_listbox + * @param rectangle A position and a size of float_listbox + * @param is_ignore_first_mouse_up The flost_listbox will be closed when a mouse_up is emitted, this parameter is specified for ignoring the first mouse_up emitting. + * @remark The float_listbox can be popupped in a mouse_down event, the next mouse_up may be ignored, otherwise the float_listbox will be closed when user releases the button. + */ + float_listbox(window, const rectangle&, bool is_ignore_first_mouse_up); + + void set_module(const module_type&, unsigned image_pixels); + void scroll_items(bool upwards); + void move_items(bool upwards, bool circle); + void renderer(item_renderer*); + std::size_t index() const; + }; +} + +#endif diff --git a/include/nana/gui/widgets/form.hpp b/include/nana/gui/widgets/form.hpp new file mode 100644 index 00000000..4f6c0aaf --- /dev/null +++ b/include/nana/gui/widgets/form.hpp @@ -0,0 +1,64 @@ +/* + * A Form Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/form.hpp + */ + +#ifndef NANA_GUI_WIDGET_FORM_HPP +#define NANA_GUI_WIDGET_FORM_HPP + +#include "widget.hpp" + +namespace nana +{ + namespace drawerbase + { + namespace form + { + class trigger: public drawer_trigger + { + public: + trigger(); + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void resized(graph_reference, const arg_resized&) override; + private: + widget* wd_; + }; + }//end namespace form + }//end namespace drawerbase + + /// \brief Pop-up window. Is different from other window widgets: its default constructor create the window. + /// \see nana::appearance + class form: public widget_object + { + public: + typedef ::nana::appear appear; + + /// Creates a window at the point and size specified by rect, and with the specified appearance. Creates a form owned by the desktop. + form(const rectangle& = API::make_center(300, 200), const appearance& = {}); //Default constructor + form(const form&, const ::nana::size& = { 300, 200 }, const appearance& = {}); //Copy constructor + form(window, const ::nana::size& = { 300, 200 }, const appearance& = {}); + /// Creates a window at the point and size specified by rect, with the specified appearance. This window is always floating above its owner. + form(window, const rectangle&, const appearance& = {}); + }; + + class nested_form : public widget_object + { + public: + typedef ::nana::appear appear; + + nested_form(const form&, const rectangle& = {}, const appearance& = {}); + nested_form(const nested_form&, const rectangle& = {}, const appearance& = {}); + + nested_form(window, const appearance&); + nested_form(window, const rectangle& = {}, const appearance& = {}); + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/frame.hpp b/include/nana/gui/widgets/frame.hpp new file mode 100644 index 00000000..0b04b4b6 --- /dev/null +++ b/include/nana/gui/widgets/frame.hpp @@ -0,0 +1,53 @@ +/* + * A Frame Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/frame.hpp + * + * A frame provides a way to contain the platform window in a stdex GUI Window + */ + +#ifndef NANA_GUI_WIDGET_FRAME_HPP +#define NANA_GUI_WIDGET_FRAME_HPP + +#include "widget.hpp" +namespace nana +{ + /** + \brief Container for system native windows. Provides an approach to + display a control that is not written with Nana.GUI in a Nana.GUI window. + + Notes: + + 1. nana::native_window_type is a type of system handle of windows. + 2. all the children windows of a nana::frame is topmost to Nana.GUI windows. + 3. a simple example. Displaying a Windows Edit Control. + + nana::frame frame(parent, 0, 0 200, 100); + HWND frame_handle = reinterpret_cast(frame.container()); + HWND edit = ::CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"Test", + WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 200, 100, + frame_handle, 0, ::GetModuleHandle(0), 0); + if(edit) + frame.insert(edit); + + */ + class frame: public widget_object + { + typedef widget_object base_type; + public: + frame(); + frame(window, bool visible); + frame(window, const rectangle& = rectangle(), bool visible = true); + bool insert(native_window_type); ///< Inserts a platform native window. + native_window_type element(unsigned index); ///< Returns the child window through index. + + native_window_type container() const; ///< Returns the frame container native window handle. + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/label.hpp b/include/nana/gui/widgets/label.hpp new file mode 100644 index 00000000..dc79eb1c --- /dev/null +++ b/include/nana/gui/widgets/label.hpp @@ -0,0 +1,78 @@ +/* + * A Label Control Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/label.hpp + */ + +#ifndef NANA_GUI_WIDGET_LABEL_HPP +#define NANA_GUI_WIDGET_LABEL_HPP +#include "widget.hpp" + + +namespace nana +{ + namespace drawerbase + { + namespace label + { + enum class command /// Defines the event type for format listener. + { + enter, leave, click + }; + + /// draw the label + class trigger: public drawer_trigger + { + public: + struct impl_t; + + trigger(); + ~trigger(); + impl_t * impl() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void click(graph_reference, const arg_mouse&) override; + private: + impl_t * impl_; + }; + + }//end namespace label + }//end namespace drawerbase + + class label + : public widget_object + { + label(const label&) = delete; + label(label&&) = delete; + public: + typedef drawerbase::label::command command; + label(); + label(window, bool visible); + label(window, const nana::string& text, bool visible = true); + label(window, const nana::char_t* text, bool visible = true); + label(window, const rectangle& = {}, bool visible = true); + label& transparent(bool); ///< Switchs the label widget to the transparent background mode. + bool transparent() const; + label& format(bool); ///< Switches the format mode of the widget. + label& add_format_listener(std::function); + + /// \briefReturn the size of the text. If *allowed_width_in_pixel* is not zero, returns a + /// "corrected" size that changes lines to fit the text into the specified width + nana::size measure(unsigned allowed_width_in_pixel) const; + + label& text_align(align horizontal_align, align_v vertical_align= align_v::top); + private: + //Overrides widget's virtual function + void _m_caption(nana::string&&) override; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp new file mode 100644 index 00000000..691e83c5 --- /dev/null +++ b/include/nana/gui/widgets/listbox.hpp @@ -0,0 +1,550 @@ +/* + * A List Box Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/listbox.hpp + * + */ + +#ifndef NANA_GUI_WIDGETS_LISTBOX_HPP +#define NANA_GUI_WIDGETS_LISTBOX_HPP +#include "widget.hpp" +#include +#include +#include +#include + +namespace nana +{ + class listbox; + + namespace drawerbase + { + namespace listbox + { + typedef std::size_t size_type; + + struct cell + { + struct format + { + ::nana::color_t bgcolor; + ::nana::color_t fgcolor; + + format(color_t bgcolor = 0xFF000000, color_t fgcolor = 0xFF000000); + }; + + using format_ptr = std::unique_ptr < format > ; + + ::nana::string text; + format_ptr custom_format; + + cell() = default; + cell(const cell&); + cell(cell&&); + cell(nana::string); + cell(nana::string, const format&); + cell(nana::string, color_t bgcolor, color_t fgcolor); + + cell& operator=(const cell&); + cell& operator=(cell&&); + }; + + class oresolver + { + public: + oresolver& operator<<(bool); + oresolver& operator<<(short); + oresolver& operator<<(unsigned short); + oresolver& operator<<(int); + oresolver& operator<<(unsigned int); + oresolver& operator<<(long); + oresolver& operator<<(unsigned long); + oresolver& operator<<(long long); + oresolver& operator<<(unsigned long long); + oresolver& operator<<(float); + oresolver& operator<<(double); + oresolver& operator<<(long double); + + oresolver& operator<<(const char*); + oresolver& operator<<(const wchar_t*); + oresolver& operator<<(const std::string&); + oresolver& operator<<(const std::wstring&); + oresolver& operator<<(std::wstring&&); + oresolver& operator<<(cell); + oresolver& operator<<(std::nullptr_t); + + std::vector && move_cells(); + private: + std::vector cells_; + }; + + class iresolver + { + public: + iresolver(const std::vector&); + + iresolver& operator>>(bool&); + iresolver& operator>>(short&); + iresolver& operator>>(unsigned short&); + iresolver& operator>>(int&); + iresolver& operator>>(unsigned int&); + iresolver& operator>>(long&); + iresolver& operator>>(unsigned long&); + iresolver& operator>>(long long&); + iresolver& operator>>(unsigned long long&); + iresolver& operator>>(float&); + iresolver& operator>>(double&); + iresolver& operator>>(long double&); + + iresolver& operator>>(std::string&); + iresolver& operator>>(std::wstring&); + iresolver& operator>>(cell&); + iresolver& operator>>(std::nullptr_t); + private: + const std::vector& cells_; + std::size_t pos_{0}; + }; + + struct index_pair + { + size_type cat; //The pos of category + size_type item; //the pos of item in a category. + + index_pair(size_type cat_pos = 0, size_type item_pos = 0) + : cat(cat_pos), + item(item_pos) + {} + + bool empty() const + { + return (npos == cat); + } + + void set_both(size_type n) + { + cat = item = n; + } + + bool is_category() const + { + return (npos != cat && npos == item); + } + + bool is_item() const + { + return (npos != cat && npos != item); + } + + bool operator==(const index_pair& r) const + { + return (r.cat == cat && r.item == item); + } + + bool operator!=(const index_pair& r) const + { + return !this->operator==(r); + } + + bool operator>(const index_pair& r) const + { + return (cat > r.cat) || (cat == r.cat && item > r.item); + } + }; + + typedef std::vector selection; + + //struct essence_t + //@brief: this struct gives many data for listbox, + // the state of the struct does not effect on member funcions, therefore all data members are public. + struct essence_t; + + struct category_t; + class drawer_header_impl; + class drawer_lister_impl; + + class trigger: public drawer_trigger + { + public: + trigger(); + ~trigger(); + essence_t& essence(); + essence_t& essence() const; + void draw(); + private: + void _m_draw_border(); + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void typeface_changed(graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void dbl_click(graph_reference, const arg_mouse&) override; + void resized(graph_reference, const arg_resized&) override; + void key_press(graph_reference, const arg_keyboard&) override; + private: + essence_t * essence_; + drawer_header_impl *drawer_header_; + drawer_lister_impl *drawer_lister_; + };//end class trigger + + class item_proxy + : public std::iterator + { + public: + item_proxy(essence_t*); + item_proxy(essence_t*, const index_pair&); + + bool empty() const; + + item_proxy & check(bool ck); + bool checked() const; + + item_proxy & select(bool); + bool selected() const; + + item_proxy & bgcolor(nana::color_t); + nana::color_t bgcolor() const; + + item_proxy& fgcolor(nana::color_t); + nana::color_t fgcolor() const; + + index_pair pos() const; + + size_type columns() const; + + item_proxy& text(size_type col, cell); + item_proxy& text(size_type col, nana::string); + nana::string text(size_type col) const; + + void icon(const nana::paint::image&); + + template + item_proxy & resolve_from(const T& t) + { + oresolver ores; + ores << t; + auto && cells = ores.move_cells(); + auto cols = columns(); + cells.resize(cols); + for (auto pos = 0; pos < cols; ++pos) + { + auto & el = cells[pos]; + if (el.text.size() == 1 && el.text[0] == nana::char_t(0)) + continue; + text(pos, std::move(el)); + } + + return *this; + } + + template + void resolve_to(T& t) const + { + iresolver ires(_m_cells()); + ires >> t; + } + + template + T* value_ptr() const + { + auto * pany = _m_value(); + return (pany ? pany->get() : nullptr); + } + + template + T & value() const + { + auto * pany = _m_value(); + if(nullptr == pany) + throw std::runtime_error("listbox::item_proxy.value() is empty"); + + T * p = pany->get(); + if(nullptr == p) + throw std::runtime_error("listbox::item_proxy.value() invalid type of value"); + return *p; + } + + template + item_proxy & value(T&& t) + { + *_m_value(true) = std::forward(t); + return *this; + } + + /// Behavior of Iterator's value_type + bool operator==(const nana::string& s) const; + bool operator==(const char * s) const; + bool operator==(const wchar_t * s) const; + + /// Behavior of Iterator + item_proxy & operator=(const item_proxy&); + + /// Behavior of Iterator + item_proxy & operator++(); + + /// Behavior of Iterator + item_proxy operator++(int); + + /// Behavior of Iterator + item_proxy& operator*(); + + /// Behavior of Iterator + const item_proxy& operator*() const; + + /// Behavior of Iterator + item_proxy* operator->(); + + /// Behavior of Iterator + const item_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const item_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const item_proxy&) const; + + //Undocumented method + essence_t * _m_ess() const; + private: + std::vector & _m_cells() const; + nana::any * _m_value(bool alloc_if_empty); + const nana::any * _m_value() const; + private: + essence_t * ess_; + category_t* cat_{nullptr}; + index_pair pos_; + }; + + class cat_proxy + : public std::iterator < std::input_iterator_tag, cat_proxy > + { + public: + cat_proxy() = default; + cat_proxy(essence_t*, size_type pos); + cat_proxy(essence_t*, category_t*); + + /// Append an item at end of the category, set_value determines whether assign T object to the value of item. + template + item_proxy append(T&& t, bool set_value = false) + { + oresolver ores; + if (set_value) + ores << t; //copy it if it is rvalue and set_value is true. + else + ores << std::forward(t); + + _m_append(ores.move_cells()); + + item_proxy iter{ ess_, index_pair(pos_, size() - 1) }; + if (set_value) + iter.value(std::forward(t)); + return iter; + } + + void append(std::initializer_list); + + size_type columns() const; + + cat_proxy& text(nana::string); + nana::string text() const; + + /// Behavior of a container + void push_back(nana::string); + + item_proxy begin() const; + item_proxy end() const; + item_proxy cbegin() const; + item_proxy cend() const; + + item_proxy at(size_type pos) const; + item_proxy back() const; + + /// Returns the index of a item by its display pos, the index of the item isn't changed after sorting. + size_type index_by_display_order(size_type disp_order) const; + size_type display_order(size_type pos) const; + size_type position() const; + + /// Returns the number of items + size_type size() const; + + /// Behavior of Iterator + cat_proxy& operator=(const cat_proxy&); + + /// Behavior of Iterator + cat_proxy & operator++(); + + /// Behavior of Iterator + cat_proxy operator++(int); + + /// Behavior of Iterator + cat_proxy& operator*(); + + /// Behavior of Iterator + const cat_proxy& operator*() const; + + /// Behavior of Iterator + cat_proxy* operator->(); + + /// Behavior of Iterator + const cat_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const cat_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const cat_proxy&) const; + private: + void _m_append(std::vector && cells); + void _m_cat_by_pos(); + private: + essence_t* ess_{nullptr}; + category_t* cat_{nullptr}; + size_type pos_{0}; + }; + } + }//end namespace drawerbase + + struct arg_listbox + { + mutable drawerbase::listbox::item_proxy item; + bool selected; + }; + + namespace drawerbase + { + namespace listbox + { + struct listbox_events + : public general_events + { + basic_event checked; + basic_event selected; + }; + } + }//end namespace drawerbase + +/*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain \a items. +A category is a text with can be \a selected, \a checked and \a expanded to show the items. +An item is formed by \a column-fields, each corresponding to one of the \a headers. +An item can be \a selected and \a checked. +The user can \a drag the header to \a reisize it or to \a reorganize it. +By \a clicking on a header the list get \a reordered, first up, and then down alternatively, +*/ + class listbox + : public widget_object, + public concepts::any_objective + { + public: + using size_type = drawerbase::listbox::size_type; + using index_pair = drawerbase::listbox::index_pair; + using cat_proxy = drawerbase::listbox::cat_proxy; + using item_proxy = drawerbase::listbox::item_proxy; + using selection = drawerbase::listbox::selection; ///); /// + cat_proxy operator[](const Key & ck) + { + typedef typename nana::detail::type_escape::type key_t; + std::shared_ptr p(new nana::key>(ck), [](nana::detail::key_interface* p) + { + delete p; + }); + + return cat_proxy(&_m_ess(), _m_at_key(p)); + } + + template + cat_proxy operator[](Key && ck) + { + typedef typename nana::detail::type_escape::type key_t; + std::shared_ptr p(new nana::key>(std::move(ck)), [](nana::detail::key_interface* p) + { + delete p; + }); + + return cat_proxy(&_m_ess(), _m_at_key(p)); + } + + item_proxy at(const index_pair&) const; + + void insert(const index_pair&, nana::string); /// + void erase_key(const Key& kv) + { + typedef typename nana::detail::type_escape::type key_t; + nana::key > key(kv); + _m_ease_key(&key); + } + + template + void erase_key(Key&& kv) + { + typedef typename nana::detail::type_escape::type key_t; + nana::key > key(std::move(kv)); + _m_ease_key(&key); + } + + ///Sets a strick weak ordering comparer for a column + void set_sort_compare(size_type col, std::function strick_ordering); + + void sort_col(size_type col, bool reverse = false); + size_type sort_col() const; + void unsort(); + bool freeze_sort(bool freeze); + + selection selected() const; ///); + void _m_ease_key(nana::detail::key_interface*); + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp new file mode 100644 index 00000000..7e072324 --- /dev/null +++ b/include/nana/gui/widgets/menu.hpp @@ -0,0 +1,200 @@ +/* + * A Menu implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2009-2014 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/gui/widgets/menu.hpp + */ + +#ifndef NANA_GUI_WIDGETS_MENU_HPP +#define NANA_GUI_WIDGETS_MENU_HPP +#include "widget.hpp" +#include +#include +#include + +namespace nana +{ + namespace drawerbase + { + namespace menu + { + struct menu_type; //declaration + + enum class checks + { + none, + option, + highlight + }; + + struct menu_item_type + { + /// This class is used as parameter of menu event function. + class item_proxy + { + public: + item_proxy(std::size_t n, menu_item_type &); + item_proxy& enabled(bool); + bool enabled() const; + + item_proxy& check_style(checks); + item_proxy& checked(bool); + bool checked() const; + + std::size_t index() const; + private: + std::size_t index_; + menu_item_type &item_; + }; + /// A callback functor type. + typedef std::function event_fn_t; + + //Default constructor initializes the item as a splitter + menu_item_type(); + menu_item_type(nana::string, const event_fn_t&); + + struct + { + bool enabled:1; + bool splitter:1; + bool checked:1; + }flags; + + menu_type *sub_menu{nullptr}; + nana::string text; + event_fn_t functor; + checks style{checks::none}; + paint::image image; + mutable nana::char_t hotkey{0}; + }; + + struct menu_type + { + typedef std::vector item_container; + typedef item_container::iterator iterator; + typedef item_container::const_iterator const_iterator; + + std::vector owner; + std::vector items; + unsigned max_pixels; + unsigned item_pixels; + nana::point gaps; + }; + + class renderer_interface + { + public: + typedef nana::paint::graphics & graph_reference; + + enum class state + { + normal, active + }; + + struct attr + { + state item_state; + bool enabled; + bool checked; + checks check_style; + }; + + virtual ~renderer_interface() = 0; + + virtual void background(graph_reference, window) = 0; + virtual void item(graph_reference, const nana::rectangle&, const attr&) = 0; + virtual void item_image(graph_reference, const nana::point&, const paint::image&) = 0; + virtual void item_text(graph_reference, const nana::point&, const nana::string&, unsigned text_pixels, const attr&) = 0; + virtual void sub_arrow(graph_reference, const nana::point&, unsigned item_pixels, const attr&) = 0; + }; + }//end namespace menu + }//end namespace drawerbase + + class menu + : private noncopyable + { + struct implement; + + //let menubar access the private _m_popup() method. + friend class menu_accessor; + public: + typedef drawerbase::menu::checks checks; + + typedef drawerbase::menu::renderer_interface renderer_interface; + typedef drawerbase::menu::menu_item_type item_type; + typedef item_type::item_proxy item_proxy; + typedef item_type::event_fn_t event_fn_t; ///< A callback functor type. Prototype: `void(item_proxy&)` + + menu(); ///< The default constructor. NO OTHER CONSTRUCTOR. + ~menu(); + + /// Appends an item to the menu. + item_proxy append(const nana::string& text, const event_fn_t& callback= event_fn_t()); + void append_splitter(); + 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(); + void image(std::size_t index, const paint::image& icon); + void check_style(std::size_t index, checks); + void checked(std::size_t index, bool); + bool checked(std::size_t index) const; + void enabled(std::size_t index, bool);///< Enables or disables the mouse or keyboard input for the item. + bool enabled(std::size_t index) const; + void erase(std::size_t index); ///< Removes the item + bool link(std::size_t index, menu& menu_obj);///< Link a menu to the item as a sub menu. + menu * link(std::size_t index); ///< Retrieves a linked sub menu of the item. + menu *create_sub_menu(std::size_t index); + void popup(window owner, int x, int y); ///< Popup the menu at the owner window. + void popup_await(window owner, int x, int y); + void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item. + void destroy_answer(const std::function&); ///< Sets an answerer for the callback while the menu window is closing. + void gaps(const nana::point&); ///< Sets the gap between a menu and its sub menus.(\See Note4) + void goto_next(bool forward); ///< Moves the focus to the next or previous item. + bool goto_submen();///< Popup the submenu of the current item if it has a sub menu. Returns true if succeeds. + bool exit_submenu(); ///< Closes the current window of the sub menu. + std::size_t size() const; ///< Return the number of items. + int send_shortkey(nana::char_t key); + void pick(); + + menu& max_pixels(unsigned); ///< Sets the max width in pixels of the item. + unsigned max_pixels() const; + + menu& item_pixels(unsigned); ///< Sets the height in pixel for the items. + unsigned item_pixels() const; + + void renderer(const pat::cloneable&); ///< Sets a user-defined renderer. + const pat::cloneable& renderer() const; + + private: + void _m_destroy_menu_window(); + void _m_popup(window, int x, int y, bool called_by_menubar); + private: + implement * impl_; + }; + + namespace detail + { + class popuper + { + public: + popuper(menu&, mouse); + popuper(menu&, window owner, const point&, mouse); + void operator()(const arg_mouse&); + private: + menu & mobj_; + window owner_; + bool take_mouse_pos_; + nana::point pos_; + mouse mouse_; + }; + } + + detail::popuper menu_popuper(menu&, mouse = mouse::right_button); + detail::popuper menu_popuper(menu&, window owner, const point&, mouse = mouse::right_button); +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/menubar.hpp b/include/nana/gui/widgets/menubar.hpp new file mode 100644 index 00000000..ef9c8ce5 --- /dev/null +++ b/include/nana/gui/widgets/menubar.hpp @@ -0,0 +1,113 @@ +/* + * A Menubar implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2009-2014 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/gui/widgets/menubar.hpp + */ + +#ifndef NANA_GUI_WIDGETS_MENUBAR_HPP +#define NANA_GUI_WIDGETS_MENUBAR_HPP +#include "widget.hpp" +#include "menu.hpp" + +namespace nana +{ + namespace drawerbase + { + namespace menubar + { + class item_renderer + { + public: + enum state_t{state_normal, state_highlight, state_selected}; + typedef nana::paint::graphics& graph_reference; + + item_renderer(window, graph_reference); + virtual void background(const nana::point& pos, const nana::size& size, state_t); + virtual void caption(int x, int y, const nana::string& text); + private: + window handle_; + graph_reference graph_; + }; + + class trigger + : public drawer_trigger + { + class itembase; + public: + trigger(); + ~trigger(); + nana::menu* push_back(const nana::string&); + nana::menu* at(size_t) const; + std::size_t size() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void focus(graph_reference, const arg_focus&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_release(graph_reference, const arg_keyboard&) override; + void shortkey(graph_reference, const arg_keyboard&) override; + private: + void _m_move(bool to_left); + bool _m_popup_menu(); + void _m_total_close(); + bool _m_close_menu(); + void _m_unload_menu_window(); + std::size_t _m_item_by_pos(const ::nana::point&); + bool _m_track_mouse(const ::nana::point&); + void _m_draw(); + private: + widget *widget_; + nana::paint::graphics *graph_; + + itembase* items_; + + struct state_type + { + enum behavior_t + { + behavior_none, behavior_focus, behavior_menu, + }; + + state_type(); + + std::size_t active; + behavior_t behavior; + + bool menu_active; + bool passive_close; + + bool nullify_mouse; + + nana::menu *menu; + nana::point mouse_pos; + }state_; + }; + }//end namespace menubar + }//end namespace drawerbase + + /// \brief A toolbar at the top of window for popuping menus. + /// + /// The widget sets as shortkey the character behind the first of & in the text, for the item. e.g. "File(&F)" or "&File". + class menubar + : public widget_object + { + public: + menubar(); ///< The default constructor delay creation. + menubar(window); ///< Create a menubar at the top of the specified window. + void create(window); ///< Create a menubar at the top of the specified window. + menu& push_back(const nana::string&); ///< Appends a new (empty) menu. + menu& at(size_t index) const; ///< Gets the menu specified by index. + std::size_t length() const; ///< Number of menus. + };//end class menubar +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp new file mode 100644 index 00000000..a9dc6a18 --- /dev/null +++ b/include/nana/gui/widgets/panel.hpp @@ -0,0 +1,71 @@ +/* + * A Panel Implementation + * Nana C++ Library(http://www.nanaro.org) + * Copyright(C) 2003-2014 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/gui/widgets/panel.hpp + * + * @brief: panel is a widget used for placing some widgets. + */ + +#ifndef NANA_GUI_WIDGETS_PANEL_HPP +#define NANA_GUI_WIDGETS_PANEL_HPP +#include "widget.hpp" +#include + +namespace nana +{ + namespace drawerbase + { + namespace panel + { + class drawer: public drawer_trigger + { + public: + drawer(); + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + private: + window window_; + }; + }// end namespace panel + }//end namespace drawerbase + /// For placing other widgets, where the bool template parameter determinte if it is widget or lite_widget, wich in actual use make no difference. + template + class panel + : public widget_object::type, + drawerbase::panel::drawer> + { + public: + panel(){} + + panel(window wd, bool visible) + { + this->create(wd, rectangle(), visible); + } + + panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) + { + this->create(wd, r, visible); + } + + bool transparent() const + { + return (bground_mode::basic == API::effects_bground_mode(*this)); + } + + void transparent(bool tr) + { + if(tr) + API::effects_bground(*this, effects::bground_transparent(0), 0); + else + API::effects_bground_remove(*this); + } + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/picture.hpp b/include/nana/gui/widgets/picture.hpp new file mode 100644 index 00000000..7238fe32 --- /dev/null +++ b/include/nana/gui/widgets/picture.hpp @@ -0,0 +1,81 @@ +/* + * A Picture Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/picture.hpp + * + * Used for showing a picture + */ +#ifndef NANA_GUI_WIDGET_PICTURE_HPP +#define NANA_GUI_WIDGET_PICTURE_HPP +#include "widget.hpp" + +namespace nana +{ + namespace xpicture + { + class picture_drawer: public drawer_trigger + { + public: + picture_drawer(); + void attached(widget_reference, graph_reference) override; + void load(const nana::char_t* file); + void load(const nana::paint::image&); + void set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal); + bool bgstyle(bool is_stretch, nana::arrange, int beg, int end); + private: + void refresh(graph_reference) override; + void _m_draw_background(); + private: + widget* widget_; + nana::paint::graphics* graph_; + + struct runtime_type + { + runtime_type(); + unsigned background_shadow_start; + unsigned background_shadow_end; + bool horizontal; + }runtime_; + + struct back_image_tag + { + nana::paint::image image; + bool is_stretch; + nana::arrange arg; + int beg, end; + }backimg_; + + }; + + }//end namespace xpicture + /// Rectangle area for displaying a bitmap file + class picture + : public widget_object + { + public: + picture(); + picture(window, bool visible); + picture(window, const rectangle& = rectangle(), bool visible = true); + + void load(const nana::paint::image&); + + /// Sets the background image style. + void bgstyle(bool stretchable, ///< if false the other arguments will be ignored + nana::arrange arg, ///< stretching the image horizontally or vertically + int beg, ///< specify the stretchy area of image. + int end ///< specify the stretchy area of image. + ); + + /// Fills a gradual change color in background. + void set_shadow_background(unsigned begin_color, unsigned end_color, bool horizontal); + void transparent(bool); + bool transparent() const; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/progress.hpp b/include/nana/gui/widgets/progress.hpp new file mode 100644 index 00000000..6b12fee5 --- /dev/null +++ b/include/nana/gui/widgets/progress.hpp @@ -0,0 +1,73 @@ +/* + * A Progress Indicator Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/progress.hpp + */ + +#ifndef NANA_GUI_WIDGET_PROGRESS_HPP +#define NANA_GUI_WIDGET_PROGRESS_HPP +#include "widget.hpp" + +namespace nana +{ + namespace drawerbase + { + namespace progress + { + class trigger: public drawer_trigger + { + public: + trigger(); + unsigned value() const; + unsigned value(unsigned); + unsigned inc(); + unsigned Max() const; + unsigned Max(unsigned); + void unknown(bool); + bool unknown() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + private: + void _m_draw(); + void _m_draw_box(graph_reference); + void _m_draw_progress(graph_reference); + bool _m_check_changing(unsigned) const; + private: + static const unsigned border = 2; + widget * widget_; + nana::paint::graphics* graph_; + unsigned draw_width_; + bool has_value_; + bool unknown_; + unsigned max_; + unsigned value_; + }; //end class drawer + } + }//end namespace drawerbase + /// \brief A progressbar widget with two styles: know, and unknow amount value (goal). + /// In unknow style the amount is ignored and the bar is scrolled when value change. + class progress + : public widget_object + { + public: + progress(); + progress(window, bool visible); + progress(window, const rectangle & = rectangle(), bool visible = true); + + unsigned value() const; + unsigned value(unsigned val); + unsigned inc(); + unsigned amount() const; + unsigned amount(unsigned value); + void unknown(bool); + bool unknown() const; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp new file mode 100644 index 00000000..26421b48 --- /dev/null +++ b/include/nana/gui/widgets/scroll.hpp @@ -0,0 +1,444 @@ +/* + * A Scroll Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/scroll.hpp + */ +#ifndef NANA_GUI_WIDGET_SCROLL_HPP +#define NANA_GUI_WIDGET_SCROLL_HPP + +#include "widget.hpp" +#include +#include + +namespace nana +{ + template class scroll; + + template + struct arg_scroll + { + scroll & widget; + }; + + namespace drawerbase + { + namespace scroll + { + template + struct scroll_events + : public general_events + { + basic_event> value_changed; + }; + + enum class buttons + { + none, forward, backward, scroll, first, second + }; + + struct metrics_type + { + typedef std::size_t size_type; + + size_type peak; + size_type range; + size_type step; + size_type value; + + buttons what; + bool pressed; + size_type scroll_length; + int scroll_pos; + int scroll_mouse_offset; + + metrics_type(); + }; + + class drawer + { + public: + struct states + { + enum{none, highlight, actived, selected}; + }; + + typedef nana::paint::graphics& graph_reference; + const static unsigned fixedsize = 16; + + drawer(metrics_type& m); + void set_vertical(bool); + buttons what(graph_reference, const point&); + void scroll_delta_pos(graph_reference, int); + void auto_scroll(); + void draw(graph_reference, buttons); + private: + bool _m_check() const; + void _m_adjust_scroll(graph_reference); + void _m_background(graph_reference); + void _m_button_frame(graph_reference, int x, int y, unsigned width, unsigned height, int state); + void _m_draw_scroll(graph_reference, int state); + void _m_draw_button(graph_reference, int x, int y, unsigned width, unsigned height, buttons what, int state); + private: + metrics_type &metrics_; + bool vertical_; + }; + + template + class trigger + : public drawer_trigger + { + public: + typedef metrics_type::size_type size_type; + + trigger() + : graph_(nullptr), drawer_(metrics_) + { + drawer_.set_vertical(Vertical); + } + + const metrics_type& metrics() const + { + return metrics_; + } + + void peak(size_type s) + { + if(graph_ && (metrics_.peak != s)) + { + metrics_.peak = s; + API::refresh_window(widget_->handle()); + } + } + + void value(size_type s) + { + if(s + metrics_.range > metrics_.peak) + s = metrics_.peak - metrics_.range; + + if(graph_ && (metrics_.value != s)) + { + metrics_.value = s; + _m_emit_value_changed(); + + API::refresh_window(*widget_); + } + } + + void range(size_type s) + { + if(graph_ && (metrics_.range != s)) + { + metrics_.range = s; + API::refresh_window(widget_->handle()); + } + } + + void step(size_type s) + { + metrics_.step = s; + } + + bool make_step(bool forward, unsigned multiple) + { + if(graph_) + { + size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step); + size_type value = metrics_.value; + if(forward) + { + size_type maxv = metrics_.peak - metrics_.range; + if(metrics_.peak > metrics_.range && value < maxv) + { + if(maxv - value >= step) + value += step; + else + value = maxv; + } + } + else if(value) + { + if(value > step) + value -= step; + else + value = 0; + } + size_type cmpvalue = metrics_.value; + metrics_.value = value; + if(value != cmpvalue) + { + _m_emit_value_changed(); + return true; + } + return false; + } + return false; + } + private: + void attached(widget_reference widget, graph_reference graph) + { + graph_ = &graph; + widget_ = static_cast< ::nana::scroll*>(&widget); + widget.caption(STR("Nana Scroll")); + + timer_.stop(); + timer_.elapse(std::bind(&trigger::_m_tick, this)); + } + + void detached() + { + graph_ = nullptr; + } + + void refresh(graph_reference graph) + { + drawer_.draw(graph, metrics_.what); + } + + void resized(graph_reference graph, const ::nana::arg_resized&) override + { + drawer_.draw(graph, metrics_.what); + API::lazy_refresh(); + } + + void mouse_enter(graph_reference graph, const ::nana::arg_mouse& arg) override + { + metrics_.what = drawer_.what(graph, arg.pos); + drawer_.draw(graph, metrics_.what); + API::lazy_refresh(); + } + + void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) + { + bool redraw = false; + if(metrics_.pressed && (metrics_.what == buttons::scroll)) + { + size_type cmpvalue = metrics_.value; + drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x)); + if(cmpvalue != metrics_.value) + _m_emit_value_changed(); + redraw = true; + } + else + { + buttons what = drawer_.what(graph, arg.pos); + if(metrics_.what != what) + { + redraw = true; + metrics_.what = what; + } + } + if(redraw) + { + drawer_.draw(graph, metrics_.what); + API::lazy_refresh(); + } + } + + void mouse_down(graph_reference graph, const arg_mouse& arg) + { + if(arg.left_button) + { + metrics_.pressed = true; + metrics_.what = drawer_.what(graph, arg.pos); + switch(metrics_.what) + { + case buttons::first: + case buttons::second: + make_step(metrics_.what == buttons::second, 1); + timer_.interval(1000); + timer_.start(); + break; + case buttons::scroll: + API::capture_window(widget_->handle(), true); + metrics_.scroll_mouse_offset = (Vertical ? arg.pos.y : arg.pos.x) - metrics_.scroll_pos; + break; + case buttons::forward: + case buttons::backward: + { + size_type cmpvalue = metrics_.value; + drawer_.auto_scroll(); + if(cmpvalue != metrics_.value) + _m_emit_value_changed(); + } + break; + default: //Ignore buttons::none + break; + } + drawer_.draw(graph, metrics_.what); + API::lazy_refresh(); + } + } + + void mouse_up(graph_reference graph, const arg_mouse& arg) + { + timer_.stop(); + + API::capture_window(widget_->handle(), false); + + metrics_.pressed = false; + metrics_.what = drawer_.what(graph, arg.pos); + drawer_.draw(graph, metrics_.what); + API::lazy_refresh(); + } + + void mouse_leave(graph_reference graph, const arg_mouse&) + { + if(metrics_.pressed) return; + + metrics_.what = buttons::none; + drawer_.draw(graph, buttons::none); + API::lazy_refresh(); + } + + void mouse_wheel(graph_reference graph, const arg_wheel& arg) + { + if(make_step(arg.upwards == false, 3)) + { + drawer_.draw(graph, metrics_.what); + API::lazy_refresh(); + } + } + private: + void _m_emit_value_changed() + { + widget_->events().value_changed.emit(::nana::arg_scroll({*widget_})); + } + + void _m_tick() + { + make_step(metrics_.what == buttons::second, 1); + API::refresh_window(widget_->handle()); + timer_.interval(100); + } + private: + ::nana::scroll * widget_; + nana::paint::graphics * graph_; + metrics_type metrics_; + drawer drawer_; + timer timer_; + }; + }//end namespace scroll + }//end namespace drawerbase + + /// Provides a way to display an object which is larger than the window's client area. + template + class scroll + : public widget_object, drawerbase::scroll::scroll_events> + { + typedef widget_object > base_type; + public: + typedef std::size_t size_type; + + /// \brief The default constructor without creating the widget. + scroll(){} + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param visible specifying the visible after creating. + scroll(window wd, bool visible) + { + this->create(wd, rectangle(), visible); + } + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param r the size and position of the widget in its parent window coordinate. + /// @param visible specifying the visible after creating. + scroll(window wd, const rectangle& r, bool visible = true) + { + this->create(wd, r, visible); + } + + /// \brief Determines whether it is scrollable. + /// @param for_less whether it can be scrolled for a less value. + bool scrollable(bool for_less) const + { + auto & m = this->get_drawer_trigger().metrics(); + return (for_less ? (0 != m.value) : (m.value < m.peak - m.range)); + } + + size_type amount() const + { + return this->get_drawer_trigger().metrics().peak; + } + + void amount(size_type Max) + { + return this->get_drawer_trigger().peak(Max); + } + + /// Get the range of the widget. + size_type range() const + { + return this->get_drawer_trigger().metrics().range; + } + + /// Set the range of the widget. + void range(size_type r) + { + return this->get_drawer_trigger().range(r); + } + + /// \brief Get the value. + /// @return the value. + size_type value() const + { + return this->get_drawer_trigger().metrics().value; + } + + /// \brief Set the value. + /// @param s a new value. + void value(size_type s) + { + return this->get_drawer_trigger().value(s); + } + + + /// \brief Get the step of the sroll widget. The step indicates a variation of the value. + /// @return the step. + size_type step() const + { + return this->get_drawer_trigger().metrics().step; + } + + /// \brief Set the step. + /// @param s a value for step. + void step(size_type s) + { + return this->get_drawer_trigger().step(s); + } + + /// \brief Increase/decrease values by a step. + /// @param forward it determines whether increase or decrease. + /// @return true if the value is changed. + bool make_step(bool forward) + { + if(this->get_drawer_trigger().make_step(forward, 1)) + { + API::refresh_window(this->handle()); + return true; + } + return false; + } + + /// \brief Increase/decrease values by steps as if it is scrolled through mouse wheel. + /// @param forward it determines whether increase or decrease. + /// @return true if the vlaue is changed. + bool make_scroll(bool forward) + { + if(this->get_drawer_trigger().make_step(forward, 3)) + { + API::refresh_window(this->handle()); + return true; + } + return false; + } + };//end class scroll +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp new file mode 100644 index 00000000..0af6b895 --- /dev/null +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -0,0 +1,335 @@ +/* + * A text editor implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/skeletons/text_editor.hpp + * @description: + */ + +#ifndef NANA_GUI_SKELETONS_TEXT_EDITOR_HPP +#define NANA_GUI_SKELETONS_TEXT_EDITOR_HPP +#include "textbase.hpp" +#include +#include +#include + +namespace nana{ namespace widgets +{ + namespace skeletons + { + template + class undoable_command_interface + { + public: + virtual ~undoable_command_interface() = default; + + virtual EnumCommand get() const = 0; + virtual bool merge(const undoable_command_interface&) = 0; + virtual void execute(bool redo) = 0; + }; + + template + class undoable + { + public: + using command = EnumCommand; + using container = std::deque < std::unique_ptr> >; + + void max_steps(std::size_t maxs) + { + max_steps_ = maxs; + if (maxs && (commands_.size() >= maxs)) + commands_.erase(commands_.begin(), commands_.begin() + (commands_.size() - maxs + 1)); + } + + std::size_t max_steps() const + { + return max_steps_; + } + + void enable(bool enb) + { + enabled_ = enb; + if (!enb) + commands_.clear(); + } + + bool enabled() const + { + return enabled_; + } + + void push(std::unique_ptr> && ptr) + { + if (!ptr || !enabled_) + return; + + if (pos_ < commands_.size()) + commands_.erase(commands_.begin() + pos_, commands_.end()); + else if (max_steps_ && (commands_.size() >= max_steps_)) + commands_.erase(commands_.begin(), commands_.begin() + (commands_.size() - max_steps_ + 1)); + + pos_ = commands_.size(); + if (!commands_.empty()) + { + if (commands_.back().get()->merge(*ptr)) + return; + } + + commands_.emplace_back(std::move(ptr)); + ++pos_; + } + + std::size_t count(bool is_undo) const + { + return (is_undo ? pos_ : commands_.size() - pos_); + } + + void undo() + { + if (pos_ > 0) + { + --pos_; + commands_[pos_].get()->execute(false); + } + } + + void redo() + { + if (pos_ != commands_.size()) + commands_[pos_++].get()->execute(true); + } + + private: + container commands_; + bool enabled_{ true }; + std::size_t max_steps_{ 30 }; + std::size_t pos_{ 0 }; + }; + + class text_editor + { + struct attributes; + class editor_behavior_interface; + class behavior_normal; + class behavior_linewrapped; + + enum class command{ + backspace, input_text, move_text, + }; + //Commands for undoable + template class basic_undoable; + class undo_backspace; + class undo_input_text; + class undo_move_text; + public: + typedef nana::char_t char_type; + typedef textbase::size_type size_type; + typedef textbase::string_type string_type; + + typedef nana::paint::graphics & graph_reference; + + struct ext_renderer_tag + { + std::function background; + }; + + text_editor(window, graph_reference); + ~text_editor(); + + bool respone_keyboard(nana::char_t, bool enterable); + + void typeface_changed(); + + /// Determine whether the text_editor is line wrapped. + bool line_wrapped() const; + /// Set the text_editor whether it is line wrapped, it returns false if the state is not changed. + bool line_wrapped(bool); + + void border_renderer(std::function); + + bool load(const nana::char_t*); + + //text_area + //@return: Returns true if the area of text is changed. + bool text_area(const nana::rectangle&); + bool tip_string(nana::string&&); + + const attributes & attr() const; + bool multi_lines(bool); + void editable(bool); + void enable_background(bool); + void enable_background_counterpart(bool); + + void undo_enabled(bool); + bool undo_enabled() const; + void undo_max_steps(std::size_t); + std::size_t undo_max_steps() const; + + ext_renderer_tag& ext_renderer() const; + + unsigned line_height() const; + unsigned screen_lines() const; + + bool getline(std::size_t pos, nana::string&) const; + void text(nana::string); + nana::string text() const; + + //move_caret + //@brief: Set caret position through text coordinate + void move_caret(const upoint&); + void move_caret_end(); + void reset_caret_height() const; + void reset_caret(); + void show_caret(bool isshow); + + bool selected() const; + bool select(bool); + //Set the end position of a selected string + void set_end_caret(); + bool hit_text_area(const point&) const; + bool hit_select_area(nana::upoint pos) const; + bool move_select(); + bool mask(char_t); + + /// Returns width of text area excluding the vscroll size. + unsigned width_pixels() const; + public: + void draw_scroll_rectangle(); + void render(bool focused); + public: + void put(nana::string); + void put(nana::char_t); + void copy() const; + void cut(); + void paste(); + void enter(bool record_undo = true); + void del(); + void backspace(bool record_undo = true); + void undo(bool reverse); + bool move(nana::char_t); + void move_ns(bool to_north); //Moves up and down + void move_left(); + void move_right(); + nana::upoint mouse_caret(const point& screen_pos); + nana::upoint caret() const; + bool scroll(bool upwards, bool vertical); + bool mouse_enter(bool); + bool mouse_down(bool left_button, const point& screen_pos); + bool mouse_move(bool left_button, const point& screen_pos); + bool mouse_up(bool left_button, const point& screen_pos); + + skeletons::textbase& textbase(); + const skeletons::textbase& textbase() const; + private: + nana::color_t _m_bgcolor() const; + bool _m_scroll_text(bool vertical); + void _m_on_scroll(const arg_mouse&); + void _m_scrollbar(); + nana::size _m_text_area() const; + void _m_get_scrollbar_size(); + void _m_reset(); + nana::upoint _m_put(nana::string); + nana::upoint _m_erase_select(); + + bool _m_make_select_string(nana::string&) const; + static bool _m_resolve_text(const nana::string&, std::vector> & lines); + + bool _m_cancel_select(int align); + unsigned _m_tabs_pixels(size_type tabs) const; + nana::size _m_text_extent_size(const char_type*) const; + nana::size _m_text_extent_size(const char_type*, size_type n) const; + + //_m_move_offset_x_while_over_border + //@brief: Moves the view window + bool _m_move_offset_x_while_over_border(int many); + bool _m_move_select(bool record_undo); + + int _m_text_top_base() const; + //_m_endx + //@brief: Gets the right point of text area + int _m_endx() const; + //_m_endy + //@brief: Get the bottom point of text area + int _m_endy() const; + + void _m_draw_tip_string() const; + + //_m_draw_string + //@brief: Draw a line of string + void _m_draw_string(int top, nana::color_t color, const nana::upoint& str_pos, const nana::string&, bool if_mask) const; + //_m_draw + //@brief: Draw a character at a position specified by caret pos. + //@return: true if beyond the border + bool _m_draw(nana::char_t, std::size_t secondary_before); + bool _m_get_sort_select_points(nana::upoint&, nana::upoint&) const; + + void _m_offset_y(int y); + + unsigned _m_char_by_pixels(const nana::char_t*, std::size_t len, unsigned* pxbuf, int str_px, int pixels, bool is_rtl); + unsigned _m_pixels_by_char(const nana::string&, std::size_t pos) const; + static bool _m_is_right_text(const unicode_bidi::entity&); + private: + std::unique_ptr behavior_; + undoable undo_; + nana::window window_; + graph_reference graph_; + skeletons::textbase textbase_; + nana::char_t mask_char_{0}; + + mutable ext_renderer_tag ext_renderer_; + + struct attributes + { + nana::string tip_string; + + bool line_wrapped{false}; + bool multi_lines{true}; + bool editable{true}; + bool enable_background{true}; + bool enable_counterpart{false}; + nana::paint::graphics counterpart; //this is used to keep the background that painted by external part. + + std::unique_ptr> vscroll; + std::unique_ptr> hscroll; + }attributes_; + + struct text_area_type + { + nana::rectangle area; + + bool captured; + unsigned tab_space; + unsigned scroll_pixels; + unsigned vscroll; + unsigned hscroll; + std::function border_renderer; + }text_area_; + + struct selection + { + enum mode_selection_t{mode_no_selected, mode_mouse_selected, mode_method_selected}; + + mode_selection_t mode_selection; + bool dragged; + nana::upoint a, b; + }select_; + + struct coordinate + { + nana::point offset; //x stands for pixels, y for lines + nana::upoint caret; //position of caret by text, it specifies the position of a new character + unsigned xpos{0}; //This data is used for move up/down + }points_; + }; + }//end namespace skeletons +}//end namespace widgets +}//end namespace nana + +#endif + diff --git a/include/nana/gui/widgets/skeletons/text_token_stream.hpp b/include/nana/gui/widgets/skeletons/text_token_stream.hpp new file mode 100644 index 00000000..a753f3f4 --- /dev/null +++ b/include/nana/gui/widgets/skeletons/text_token_stream.hpp @@ -0,0 +1,952 @@ +/* + * Text Token Stream + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2013 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/gui/widgets/skeletons/text_token_stream.hpp + */ + +#ifndef NANA_GUI_WIDGETS_SKELETONS_TEXT_TOKEN_STREAM +#define NANA_GUI_WIDGETS_SKELETONS_TEXT_TOKEN_STREAM + +#include + +#include +#include +#include +#include +#include +#include + +namespace nana{ namespace widgets{ namespace skeletons +{ + //The tokens are defined for representing a text, the tokens are divided + //into two parts. + //Formatted tokens: The tokens present in a format block, they form the format-syntax. + //Data tokens: The tokens present a text displaying on the screen. + enum class token + { + tag_begin, tag_end, format_end, + font, bold, size, color, url, target, image, top, center, bottom, baseline, + number, string, _true, _false, red, green, blue, white, black, binary, min_limited, max_limited, + + equal, comma, backslash, + data, endl, + eof + }; + + class tokenizer + { + public: + tokenizer(const nana::string& s, bool format_enabled) + : iptr_(s.data()), + endptr_(s.data() + s.size()), + format_enabled_(format_enabled), + format_state_(false), + revert_token_(token::eof) + { + } + + void push(token tk) + { + revert_token_ = tk; + } + + //Read the token. + token read() + { + if(revert_token_ != token::eof) + { + token tk = revert_token_; + revert_token_ = token::eof; + return tk; + } + + if(iptr_ == endptr_) + return token::eof; + + //Check whether it is a format token. + if(format_enabled_ && format_state_) + return _m_format_token(); + + return _m_token(); + } + + const nana::string& idstr() const + { + return idstr_; + } + + const std::pair& binary() const + { + return binary_; + } + + std::pair binary_number() const + { + std::stringstream ss; + ss<(nana::charset(binary_.first))<<' '<(nana::charset(binary_.second)); + + std::pair r; + ss>>r.first>>r.second; + return r; + } + + int number() const + { + std::stringstream ss; + ss<(nana::charset(idstr_)); + + //It's a hex number. + if(idstr_.size() > 2 && idstr_[0] == '0' && (idstr_[1] == 'x' || idstr_[1] == 'X')) + ss>>std::hex; + + int n; + ss>>n; + return n; + } + private: + static bool _m_unicode_word_breakable(nana::char_t ch) + { + return ((0x4E00 <= ch) && (ch <= 0x9FFF)); + } + + //Read the data token + token _m_token() + { + nana::char_t ch = *iptr_; + + if(ch > 0xFF) + { + //This is the Unicode. + + idstr_.clear(); + idstr_.append(1, ch); + + if(_m_unicode_word_breakable(ch)) + { + ++iptr_; + return token::data; + } + + ch = *++iptr_; + while((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(ch))) + { + idstr_.append(1, ch); + + ch = *++iptr_; + } + + return token::data; + } + + if('\n' == ch) + { + ++iptr_; + return token::endl; + } + + if(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) + { + const nana::char_t * idstr = iptr_; + do + { + ch = *(++iptr_); + } + while(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')); + + idstr_.assign(idstr, iptr_); + + return token::data; + } + + if('0' <= ch && ch <= '9') + { + _m_read_number(); + return token::data; + } + + if(('<' == ch) && format_enabled_) + { + //pos keeps the current position, and it used for restring + //iptr_ when the search is failed. + const nana::char_t * pos = ++iptr_; + _m_eat_whitespace(); + if(*iptr_ == '/') + { + ++iptr_; + _m_eat_whitespace(); + if(*iptr_ == '>') + { + ++iptr_; + return token::format_end; + } + } + + //Restore the iptr_; + iptr_ = pos; + + format_state_ = true; + return token::tag_begin; + } + + //Escape + if(ch == '\\') + { + if(iptr_ + 1 < endptr_) + { + ch = *(iptr_ + 1); + iptr_ += 2; + } + else + { + iptr_ = endptr_; + return token::eof; + } + } + + ++iptr_; + + idstr_.clear(); + idstr_.append(1, ch); + return token::data; + } + + //Read the format token + token _m_format_token() + { + _m_eat_whitespace(); + + nana::char_t ch = *iptr_++; + + switch(ch) + { + case ',': return token::comma; + case '/': return token::backslash; + case '=': return token::equal; + case '>': + format_state_ = false; + return token::tag_end; + case '"': + //Here is a string and all the meta characters will be ignored except " + { + const nana::char_t * str = iptr_; + + while((iptr_ != endptr_) && (*iptr_ != '"')) + ++iptr_; + + idstr_.assign(str, iptr_++); + } + return token::string; + case '(': + _m_eat_whitespace(); + if((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + { + const nana::char_t * pbegin = iptr_; + while((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + ++iptr_; + + binary_.first.assign(pbegin, iptr_); + + _m_eat_whitespace(); + if((iptr_ < endptr_) && (',' == *iptr_)) + { + ++iptr_; + _m_eat_whitespace(); + if((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + { + pbegin = iptr_; + while((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + ++iptr_; + + binary_.second.assign(pbegin, iptr_); + + _m_eat_whitespace(); + if((iptr_ < endptr_) && (')' == *iptr_)) + { + ++iptr_; + return token::binary; + } + } + } + } + return token::eof; + } + + if(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || '_' == ch) + { + --iptr_; + //Here is a identifier + _m_read_idstr(); + + if(STR("font") == idstr_) + return token::font; + else if(STR("bold") == idstr_) + return token::bold; + else if(STR("size") == idstr_) + return token::size; + else if(STR("baseline") == idstr_) + return token::baseline; + else if(STR("top") == idstr_) + return token::top; + else if(STR("center") == idstr_) + return token::center; + else if(STR("bottom") == idstr_) + return token::bottom; + else if(STR("color") == idstr_) + return token::color; + else if(STR("image") == idstr_) + return token::image; + else if(STR("true") == idstr_) + return token::_true; + else if(STR("url") == idstr_) + return token::url; + else if(STR("target") == idstr_) + return token::target; + else if(STR("false") == idstr_) + return token::_false; + else if(STR("red") == idstr_) + return token::red; + else if(STR("green") == idstr_) + return token::green; + else if(STR("blue") == idstr_) + return token::blue; + else if(STR("white") == idstr_) + return token::white; + else if(STR("black") == idstr_) + return token::black; + else if(STR("min_limited") == idstr_) + return token::min_limited; + else if(STR("max_limited") == idstr_) + return token::max_limited; + + return token::string; + } + + if('0' <= ch && ch <= '9') + { + --iptr_; + _m_read_number(); + return token::number; + } + + return token::eof; + } + + static bool _m_is_idstr_element(nana::char_t ch) + { + return (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('_' == ch) || ('0' <= ch && ch <= '9')); + } + + //Read the identifier. + void _m_read_idstr() + { + const nana::char_t * idstr = iptr_; + + nana::char_t ch; + do + { + ch = *(++iptr_); + } + while(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('_' == ch) || ('0' <= ch && ch <= '9')); + + idstr_.assign(idstr, iptr_); + } + + //Read the number + void _m_read_number() + { + idstr_.clear(); + + nana::char_t ch = *iptr_; + + idstr_ += ch; + + //First check the number whether will be a hex number. + if('0' == ch) + { + ch = *++iptr_; + if((!('0' <= ch && ch <= '9')) && (ch != 'x' && ch != 'X')) + return; + + if(ch == 'x' || ch == 'X') + { + //Here is a hex number + idstr_ += 'x'; + ch = *++iptr_; + while(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')) + { + idstr_ += ch; + ch = *++iptr_; + } + return; + } + + //Here is not a hex number + idstr_ += ch; + } + + ch = *++iptr_; + while('0' <= ch && ch <= '9') + { + idstr_ += ch; + ch = *++iptr_; + } + } + + void _m_eat_whitespace() + { + while(true) + { + switch(*iptr_) + { + case ' ': + case '\t': + ++iptr_; + break; + default: + return; + } + } + } + private: + const nana::char_t * iptr_; + const nana::char_t * endptr_; + const bool format_enabled_; + bool format_state_; + + nana::string idstr_; + std::pair binary_; + + std::size_t whspace_size_; + + token revert_token_; + }; + + //The fblock states a format, and a format from which it is inherted + struct fblock + { + struct aligns + { + enum t + { + top, center, bottom, + baseline + }; + }; + + nana::string font; + std::size_t font_size; + bool bold; + bool bold_empty; //bold should be ignored if bold_empty is true + aligns::t text_align; + nana::color_t bgcolor; //If the color is not specified, it will be ignored, and the system will search for its parent. + nana::color_t fgcolor; //ditto + + nana::string target; + nana::string url; + + fblock * parent; + }; + + //The abstruct data class states a data. + class data + { + public: + typedef nana::paint::graphics& graph_reference; + + virtual ~data(){} + + virtual bool is_text() const = 0; + virtual bool is_whitespace() const = 0; + virtual const nana::string& text() const = 0; + virtual void measure(graph_reference) = 0; + virtual void nontext_render(graph_reference, int x, int y) = 0; + virtual const nana::size & size() const = 0; + virtual std::size_t ascent() const = 0; + }; + + + class data_text + : public data + { + public: + data_text(const nana::string& s) + : str_(s) + {} + private: + virtual bool is_text() const override + { + return true; + } + + virtual bool is_whitespace() const override + { + return false; + } + + virtual const nana::string& text() const override + { + return str_; + } + + virtual void measure(graph_reference graph) override + { + size_ = graph.text_extent_size(str_); + unsigned ascent; + unsigned descent; + unsigned internal_leading; + graph.text_metrics(ascent, descent, internal_leading); + ascent_ = ascent; + } + + virtual void nontext_render(graph_reference, int, int) override + { + } + + virtual const nana::size & size() const override + { + return size_; + } + + virtual std::size_t ascent() const override + { + return ascent_; + } + private: + nana::string str_; + nana::size size_; + std::size_t ascent_; + }; + + class data_image + : public data + { + public: + data_image(const nana::string& imgpath, const nana::size & sz, std::size_t limited) + : image_(imgpath), limited_(limited) + { + size_ = image_.size(); + + if(sz.width != 0 && sz.height != 0) + { + bool make_fit = false; + switch(limited) + { + case 1: + make_fit = (size_.width < sz.width || size_.height < sz.height); + break; + case 2: + make_fit = (size_.width > sz.width || size_.height > sz.height); + break; + } + + if(make_fit) + { + nana::size res; + nana::fit_zoom(size_, sz, res); + size_ = res; + } + else + size_ = sz; + } + } + private: + //implement data interface + virtual bool is_text() const override + { + return false; + } + + virtual bool is_whitespace() const override + { + return false; + } + + virtual const nana::string& text() const override + { + return str_; + } + + virtual void measure(graph_reference) override + { + } + + virtual void nontext_render(graph_reference graph, int x, int y) override + { + if(size_ != image_.size()) + image_.stretch(image_.size(), graph, nana::rectangle(x, y, size_.width, size_.height)); + else + image_.paste(graph, x, y); + } + + virtual const nana::size & size() const override + { + return size_; + } + + virtual std::size_t ascent() const override + { + return size_.height; + } + private: + nana::string str_; + nana::paint::image image_; + nana::size size_; + std::size_t limited_; + }; + + class dstream + { + struct value + { + fblock * fblock_ptr; + data * data_ptr; + }; + public: + typedef std::list >::iterator iterator; + typedef std::deque linecontainer; + + ~dstream() + { + close(); + } + + void close() + { + for(auto & values: lines_) + { + for(std::deque::iterator u = values.begin(); u != values.end(); ++u) + delete u->data_ptr; + } + + lines_.clear(); + + for(auto p : fblocks_) + delete p; + + fblocks_.clear(); + } + + void parse(const nana::string& s, bool format_enabled) + { + close(); + + tokenizer tknizer(s, format_enabled); + std::stack fstack; + + fstack.push(_m_create_default_fblock()); + + while(true) + { + token tk = tknizer.read(); + + switch(tk) + { + case token::data: + _m_data_factory(tk, tknizer.idstr(), fstack.top(), lines_.back()); + break; + case token::endl: + lines_.emplace_back(); + break; + case token::tag_begin: + _m_parse_format(tknizer, fstack); + + if(attr_image_.path.size()) + { + _m_data_image(fstack.top(), lines_.back()); + //This fblock just serves the image. So we should restore the pervious fblock + fstack.pop(); + } + + break; + case token::format_end: + if(fstack.size() > 1) + fstack.pop(); + break; + case token::eof: + return; + default: + int * debug = 0; //for debug. + *debug = 0; + } + } + } + + iterator begin() + { + return lines_.begin(); + } + + iterator end() + { + return lines_.end(); + } + + private: + void _m_parse_format(tokenizer & tknizer, std::stack & fbstack) + { + fblock * fp = _m_inhert_from(fbstack.top()); + + attr_image_.reset(); + + while(true) + { + switch(tknizer.read()) + { + case token::comma: //Eat the comma, now the comma can be omitted. + break; + case token::eof: + case token::tag_end: + fblocks_.push_back(fp); + fbstack.push(fp); + return; + case token::font: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + if(token::string != tknizer.read()) + throw std::runtime_error(""); + + fp->font = tknizer.idstr(); + break; + case token::size: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + switch(tknizer.read()) + { + case token::number: + fp->font_size = tknizer.number(); + break; + case token::binary: + { + auto value = tknizer.binary_number(); + attr_image_.size.width = value.first; + attr_image_.size.height = value.second; + } + break; + default: + throw std::runtime_error(""); + } + break; + case token::color: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + switch(tknizer.read()) + { + case token::number: + fp->fgcolor = tknizer.number(); + break; + case token::red: + fp->fgcolor = 0xFF0000; + break; + case token::green: + fp->fgcolor = 0xFF00; + break; + case token::blue: + fp->fgcolor = 0xFF; + break; + case token::white: + fp->fgcolor = 0xFFFFFF; + break; + case token::black: + fp->fgcolor = 0x0; + break; + default: + throw std::runtime_error(""); + } + break; + case token::red: //support the omitting of color. + fp->fgcolor = 0xFF0000; + break; + case token::green: //support the omitting of color. + fp->fgcolor = 0xFF00; + break; + case token::blue: //support the omitting of color. + fp->fgcolor = 0xFF; + break; + case token::white: //support the omitting of color. + fp->fgcolor = 0xFFFFFF; + break; + case token::black: //support the omitting of color. + fp->fgcolor = 0x0; + break; + case token::baseline: + fp->text_align = fblock::aligns::baseline; + break; + case token::top: + fp->text_align = fblock::aligns::top; + break; + case token::center: + fp->text_align = fblock::aligns::center; + break; + case token::bottom: + fp->text_align = fblock::aligns::bottom; + break; + case token::image: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + if(token::string != tknizer.read()) + throw std::runtime_error(""); + + attr_image_.path = tknizer.idstr(); + break; + case token::min_limited: + attr_image_.limited = 1; + break; + case token::max_limited: + attr_image_.limited = 2; + break; + case token::target: + if(token::equal != tknizer.read()) + throw std::runtime_error("error: a '=' is required behind 'target'"); + + if(token::string != tknizer.read()) + throw std::runtime_error("error: the value of 'target' should be a string"); + + fp->target = tknizer.idstr(); + break; + case token::url: + if(token::equal != tknizer.read()) + throw std::runtime_error("error: a '=' is required behind 'url'"); + + if(token::string != tknizer.read()) + throw std::runtime_error("error: the value of 'url' should be a string"); + + fp->url = tknizer.idstr(); + break; + case token::bold: + { + token tk = tknizer.read(); + if(token::equal == tk) + { + switch(tknizer.read()) + { + case token::_true: + fp->bold = true; + break; + case token::_false: + fp->bold = false; + break; + default: + throw std::runtime_error(""); + } + } + else + { + tknizer.push(tk); + fp->bold = true; + } + fp->bold_empty = false; + } + break; + default: + throw std::runtime_error(""); + } + } + } + + fblock* _m_create_default_fblock() + { + //Make sure that there is not a fblock is created. + if(fblocks_.size()) + return fblocks_.front(); + + //Create a default fblock. + fblock * fbp = new fblock; + + fbp->font_size = 0xFFFFFFFF; + fbp->bold = false; + fbp->bold_empty = true; + fbp->text_align = fblock::aligns::baseline; + + //Refer to the definition for the color specification. + fbp->bgcolor = 0xFFFFFFFF; + fbp->fgcolor = 0xFFFFFFFF; + + fbp->parent = nullptr; + + fblocks_.push_back(fbp); + lines_.emplace_back(); + + return fbp; + } + + fblock * _m_inhert_from(fblock* fp) + { + fblock * fbp = new fblock; + + fbp->font = fp->font; + fbp->font_size = fp->font_size; + fbp->bold = fp->bold; + fbp->bold_empty = fp->bold_empty; + fbp->text_align = fp->text_align; + + fbp->bgcolor = fp->bgcolor; + fbp->fgcolor = fp->fgcolor; + + fbp->target = fp->target; + + fbp->parent = fp; + + return fbp; + } + + void _m_data_factory(token tk, const nana::string& idstr, fblock* fp, std::deque& line) + { + value v; + v.fblock_ptr = fp; + + switch(tk) + { + case token::data: + v.data_ptr = new data_text(idstr); + break; + default: + int * debug = 0; //for debug + *debug = 0; + } + + line.push_back(v); + } + + void _m_data_image(fblock* fp, std::deque& line) + { + value v; + v.fblock_ptr = fp; + + v.data_ptr = new data_image(attr_image_.path, attr_image_.size, attr_image_.limited); + + line.push_back(v); + } + + private: + bool format_enabled_; + std::vector fblocks_; + std::list > lines_; + + struct attr_image_tag + { + nana::string path; + nana::size size; + std::size_t limited; + + void reset() + { + path.clear(); + size.width = size.height = 0; + limited = 0; + } + }attr_image_; + }; +}//end namespace skeletons +}//end namespace widgets +}//end namepsace nana +#endif //NANA_GUI_WIDGETS_SKELETONS_TEXT_TOKEN_STREAM diff --git a/include/nana/gui/widgets/skeletons/textbase.hpp b/include/nana/gui/widgets/skeletons/textbase.hpp new file mode 100644 index 00000000..3c1cae59 --- /dev/null +++ b/include/nana/gui/widgets/skeletons/textbase.hpp @@ -0,0 +1,539 @@ +/* + * A textbase class implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/skeletons/textbase.hpp + * @description: This class manages the multi-line text and provides some operation on text + */ + +#ifndef NANA_GUI_WIDGET_DETAIL_TEXTBASE_HPP +#define NANA_GUI_WIDGET_DETAIL_TEXTBASE_HPP + +#include +#include +#include +#include "textbase_export_interface.hpp" + +#include +#include +#include +#include + +namespace nana +{ +namespace widgets +{ +namespace skeletons +{ + template + class textbase + : public ::nana::noncopyable + { + public: + typedef CharT char_type; + typedef std::basic_string string_type; + typedef typename string_type::size_type size_type; + + textbase() + { + attr_max_.reset(); + //Insert an empty string for the first line of empty text. + text_cont_.emplace_back(); + } + + void set_event_agent(textbase_event_agent_interface * evt) + { + evt_agent_ = evt; + } + + bool empty() const + { + return (text_cont_.empty() || + ((text_cont_.size() == 1) && (text_cont_[0].empty()))); + } + + bool load(const nana::char_t* fs) + { + if (nullptr == fs) + return false; + + std::string fs_mbs = nana::charset(fs); + std::ifstream ifs(fs_mbs.data()); + if (!ifs) + return false; + + ifs.seekg(0, std::ios::end); + std::size_t bytes = static_cast(ifs.tellg()); + ifs.seekg(0, std::ios::beg); + + if(bytes >= 2) + { + int ch = ifs.get(); + if(0xEF == ch && bytes >= 3) + { + //UTF8 + ch = ifs.get(); + if(0xBB == ch && 0xBF == ifs.get()) + { + ifs.close(); + return load(fs, nana::unicode::utf8); + } + } + else if(0xFF == ch) + { + if(0xFE == ifs.get()) + { + //UTF16,UTF32 + if(bytes >= 4) + { + if(ifs.get() == 0 && ifs.get() == 0) + { + ifs.close(); + return load(fs, nana::unicode::utf32); + } + } + ifs.close(); + return load(fs, nana::unicode::utf16); + } + } + else if(0xFE == ch) + { + if(ifs.get() == 0xFF) + { + //UTF16(big-endian) + ifs.close(); + return load(fs, nana::unicode::utf16); + } + } + else if(0 == ch) + { + if(bytes >= 4 && ifs.get() == 0) + { + ch = ifs.get(); + if(0xFE == ch && ifs.get() == 0xFF) + { + //UTF32(big_endian) + ifs.close(); + return load(fs, nana::unicode::utf32); + } + } + } + } + + ifs.clear(); + ifs.seekg(0, std::ios::beg); + + text_cont_.clear(); //Clear only if the file can be opened. + attr_max_.reset(); + + std::string str_mbs; + while(ifs.good()) + { + std::getline(ifs, str_mbs); + text_cont_.emplace_back(nana::charset(str_mbs)); + if(text_cont_.back().size() > attr_max_.size) + { + attr_max_.size = text_cont_.back().size(); + attr_max_.line = text_cont_.size() - 1; + } + } + + _m_saved(fs); + return true; + } + + static void byte_order_translate_2bytes(std::string& str) + { + char * s = const_cast(str.c_str()); + char * end = s + str.size(); + for(; s < end; s += 2) + { + char c = *s; + *s = *(s + 1); + *(s + 1) = c; + } + } + + static void byte_order_translate_4bytes(std::string& str) + { + char * s = const_cast(str.c_str()); + char * end = s + str.size(); + for(; s < end; s += 4) + { + char c = *s; + *s = *(s + 3); + *(s + 3) = c; + + c = *(s + 1); + *(s + 1) = *(s + 2); + *(s + 2) = c; + } + } + + bool load(const nana::char_t * fs, nana::unicode encoding) + { + if (nullptr == fs) + return false; + + std::string fs_mbs = nana::charset(fs); + std::ifstream ifs(fs_mbs.data()); + + if (!ifs) + return false; + + std::string str; + bool big_endian = true; + + if(ifs.good()) + { + text_cont_.clear(); //Clear only if the file can be opened. + attr_max_.reset(); + + std::getline(ifs, str); + + std::size_t len_of_BOM = 0; + switch(encoding) + { + case nana::unicode::utf8: + len_of_BOM = 3; break; + case nana::unicode::utf16: + len_of_BOM = 2; break; + case nana::unicode::utf32: + len_of_BOM = 4; break; + default: + throw std::runtime_error("Specified a wrong UTF"); + } + + big_endian = (str[0] == 0x00 || str[0] == char(0xFE)); + str.erase(0, len_of_BOM); + if(big_endian) + { + if(nana::unicode::utf16 == encoding) + byte_order_translate_2bytes(str); + else + byte_order_translate_4bytes(str); + } + + text_cont_.emplace_back(nana::charset(str, encoding)); + + attr_max_.size = text_cont_.back().size(); + attr_max_.line = 0; + } + + while(ifs.good()) + { + std::getline(ifs, str); + + if(big_endian) + { + if(nana::unicode::utf16 == encoding) + byte_order_translate_2bytes(str); + else + byte_order_translate_4bytes(str); + } + + text_cont_.emplace_back(nana::charset(str, encoding)); + if(text_cont_.back().size() > attr_max_.size) + { + attr_max_.size = text_cont_.back().size(); + attr_max_.line = text_cont_.size() - 1; + } + } + + _m_saved(fs); + return true; + } + + void store(nana::string fs) const + { + std::string fs_mbs = nana::charset(fs); + std::ofstream ofs(fs_mbs.data(), std::ios::binary); + if(ofs && text_cont_.size()) + { + if(text_cont_.size() > 1) + { + for(auto i = text_cont_.cbegin(), end = text_cont_.cend() - 1; i != end; ++i) + { + std::string mbs = nana::charset(*i); + ofs.write(mbs.c_str(), mbs.size()); + ofs.write("\r\n", 2); + } + } + std::string mbs = nana::charset(text_cont_.back()); + ofs.write(mbs.c_str(), mbs.size()); + _m_saved(std::move(fs)); + } + } + + void store(nana::string fs, nana::unicode encoding) const + { + std::string fs_mbs = nana::charset(fs); + std::ofstream ofs(fs_mbs.data(), std::ios::binary); + if(ofs && text_cont_.size()) + { + const char * le_boms[] = {"\xEF\xBB\xBF", "\xFF\xFE", "\xFF\xFE\x0\x0"}; //BOM for little-endian + int bytes = 0; + switch(encoding) + { + case nana::unicode::utf8: + bytes = 3; break; + case nana::unicode::utf16: + bytes = 2; break; + case nana::unicode::utf32: + bytes = 4; break; + } + + if(bytes) + ofs.write(le_boms[static_cast(encoding)], bytes); + + if(text_cont_.size() > 1) + { + std::string mbs; + for(auto i = text_cont_.cbegin(), end = text_cont_.cend() - 1; i != end; ++i) + { + mbs = nana::charset(*i).to_bytes(encoding); + mbs += "\r\n"; + ofs.write(mbs.c_str(), static_cast(mbs.size())); + } + } + std::string mbs = nana::charset(text_cont_.back()).to_bytes(encoding); + ofs.write(mbs.c_str(), static_cast(mbs.size())); + _m_saved(std::move(fs)); + } + } + + size_type lines() const + { + return text_cont_.size(); + } + + const string_type& getline(size_type pos) const + { + if(pos < text_cont_.size()) + return text_cont_[pos]; + + return nullstr_; + } + + std::pair max_line() const + { + return std::make_pair(attr_max_.line, attr_max_.size); + } + public: + void replace(size_type pos, string_type && text) + { + if(text_cont_.size() <= pos) + { + text_cont_.emplace_back(std::move(text)); + pos = text_cont_.size() - 1; + } + else + text_cont_[pos].swap(text); + + _m_make_max(pos); + _m_edited(); + } + + void insert(upoint pos, string_type && str) + { + if(pos.y < text_cont_.size()) + { + string_type& lnstr = text_cont_[pos.y]; + + if(pos.x < lnstr.size()) + lnstr.insert(pos.x, str); + else + lnstr += str; + } + else + { + text_cont_.emplace_back(std::move(str)); + pos.y = static_cast(text_cont_.size() - 1); + } + + _m_make_max(pos.y); + _m_edited(); + } + + void insertln(size_type pos, string_type&& str) + { + if(pos < text_cont_.size()) + text_cont_.emplace(text_cont_.begin() + pos, std::move(str)); + else + text_cont_.emplace_back(std::move(str)); + + _m_make_max(pos); + _m_edited(); + } + + void erase(size_type line, size_type pos, size_type count) + { + if (line < text_cont_.size()) + { + string_type& lnstr = text_cont_[line]; + if ((pos == 0) && (count >= lnstr.size())) + lnstr.clear(); + else + lnstr.erase(pos, count); + + if (attr_max_.line == line) + _m_scan_for_max(); + + _m_edited(); + } + } + + bool erase(size_type pos, std::size_t n) + { + //Bounds checking + if ((pos >= text_cont_.size()) || (0 == n)) + return false; + + if (pos + n > text_cont_.size()) + n = text_cont_.size() - pos; + + text_cont_.erase(text_cont_.begin() + pos, text_cont_.begin() + (pos + n)); + + if (pos <= attr_max_.line && attr_max_.line < pos + n) + _m_scan_for_max(); + else if (pos < attr_max_.line) + attr_max_.line -= n; + + _m_edited(); + return true; + } + + void erase_all() + { + std::deque().swap(text_cont_); + attr_max_.reset(); + _m_saved(nana::string()); + } + + void merge(size_type pos) + { + if(pos + 1 < text_cont_.size()) + { + text_cont_[pos] += text_cont_[pos + 1]; + text_cont_.erase(text_cont_.begin() + (pos + 1)); + _m_make_max(pos); + if(pos < attr_max_.line) + --attr_max_.line; + + _m_edited(); + } + } + + const nana::string& filename() const + { + return filename_; + } + + bool edited() const + { + return changed_; + } + + void edited_reset() + { + changed_ = false; + } + + void reset() + { + filename_.clear(); + changed_ = false; + } + + bool saved() const + { + return ! not_saved(); + } + + bool not_saved() const + { + return edited() || filename_.empty(); + } + private: + void _m_make_max(std::size_t pos) + { + const string_type& str = text_cont_[pos]; + if(str.size() > attr_max_.size) + { + attr_max_.size = str.size(); + attr_max_.line = pos; + } + } + + void _m_scan_for_max() + { + attr_max_.size = 0; + std::size_t n = 0; + for(auto & s : text_cont_) + { + if(s.size() > attr_max_.size) + { + attr_max_.size = s.size(); + attr_max_.line = n; + } + ++n; + } + } + + void _m_first_change() const + { + if (evt_agent_) + evt_agent_->first_change(); + } + + void _m_saved(nana::string && filename) const + { + if(filename_ != filename) + { + filename_ = std::move(filename); + _m_first_change(); + } + else if(changed_) + _m_first_change(); + + changed_ = false; + } + + void _m_edited() + { + if(!changed_) + { + _m_first_change(); + changed_ = true; + } + } + private: + std::deque text_cont_; + textbase_event_agent_interface* evt_agent_{ nullptr }; + + mutable bool changed_{ false }; + mutable nana::string filename_; //A string for the saved filename. + const string_type nullstr_; + + struct attr_max + { + std::size_t line; + std::size_t size; + + void reset() + { + line = 0; + size = 0; + } + }attr_max_; + }; + +}//end namespace detail +}//end namespace widgets +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp b/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp new file mode 100644 index 00000000..6f474721 --- /dev/null +++ b/include/nana/gui/widgets/skeletons/textbase_export_interface.hpp @@ -0,0 +1,32 @@ +/* + * Definitions of textbase export interfaces + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/skeletons/textbase_export_interface.hpp + * @description: It is defined outside, some headers like textbox should not include a whole textbase for its ext_evtbase + * + */ + +#ifndef NANA_GUI_WIDGET_TEXTBASE_EXPORT_INTERFACE_HPP +#define NANA_GUI_WIDGET_TEXTBASE_EXPORT_INTERFACE_HPP + +namespace nana{ namespace widgets +{ + namespace skeletons + { + class textbase_event_agent_interface + { + public: + virtual ~textbase_event_agent_interface() = default; + + virtual void first_change() = 0; ///< An event for the text first change after text has been opened or stored. + }; + }//end namespace skeletons +}//end namespace widgets +}//end namespace nana +#endif //NANA_GUI_WIDGET_TEXTBASE_EXPORT_INTERFACE_HPP diff --git a/include/nana/gui/widgets/slider.hpp b/include/nana/gui/widgets/slider.hpp new file mode 100644 index 00000000..51ada7e5 --- /dev/null +++ b/include/nana/gui/widgets/slider.hpp @@ -0,0 +1,142 @@ +/* + * A Slider Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/slider.hpp + */ +#ifndef NANA_GUI_WIDGETS_SLIDER_HPP +#define NANA_GUI_WIDGETS_SLIDER_HPP +#include "widget.hpp" +#include + +namespace nana +{ + class slider; + + struct arg_slider + { + slider & widget; + }; + + namespace drawerbase + { + namespace slider + { + struct slider_events + : public general_events + { + basic_event value_changed; + }; + + enum class seekdir + { + bilateral, forward, backward + }; + + class provider + { + public: + virtual ~provider() = 0; + virtual nana::string adorn_trace(unsigned vmax, unsigned vadorn) const = 0; + }; + + class renderer + { + public: + typedef ::nana::paint::graphics & graph_reference; + + struct bar_t + { + bool horizontal; + nana::rectangle r; //the rectangle of bar. + unsigned border_size; //border_size of bar. + }; + + struct slider_t + { + bool horizontal; + int pos; + unsigned border; + unsigned scale; + }; + + struct adorn_t + { + bool horizontal; + nana::point bound; + int fixedpos; + unsigned block; + unsigned vcur_scale; //pixels of vcur scale. + }; + + virtual ~renderer() = 0; + + virtual void background(window, graph_reference, bool isglass) = 0; + virtual void adorn(window, graph_reference, const adorn_t&) = 0; + virtual void adorn_textbox(window, graph_reference, const nana::string&, const nana::rectangle&) = 0; + virtual void bar(window, graph_reference, const bar_t&) = 0; + virtual void slider(window, graph_reference, const slider_t&) = 0; + }; + + class controller; + + class trigger + : public drawer_trigger + { + public: + typedef controller controller_t; + + trigger(); + ~trigger(); + controller_t* ctrl() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void resized(graph_reference, const arg_resized&) override; + private: + controller_t * impl_; + }; + }//end namespace slider + }//end namespace drawerbase + /// A slider widget wich the user can drag for tracking + class slider + : public widget_object + { + public: + typedef drawerbase::slider::renderer renderer; ///< The interface for user-defined renderer. + typedef drawerbase::slider::provider provider; ///< The interface for user-defined provider. + typedef drawerbase::slider::seekdir seekdir; ///< Defines the slider seek direction. + + slider(); + slider(window, bool visible); + slider(window, const rectangle& = rectangle(), bool visible = true); + + void seek(seekdir); ///< Define the direction that user can seek by using mouse. + void vertical(bool); + bool vertical() const; + void vmax(unsigned); + unsigned vmax() const; + void value(unsigned); + unsigned value() const; + unsigned move_step(bool forward); ///< Increase or decrease the value of slider. + unsigned adorn() const; + + pat::cloneable& ext_renderer(); ///< Refers to the current renderer that slider is using. + void ext_renderer(const pat::cloneable&); ///< Set the current renderer. + void ext_provider(const pat::cloneable&); + void transparent(bool); + bool transparent() const; + }; +}//end namespace nana + +#endif diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp new file mode 100644 index 00000000..3e265a55 --- /dev/null +++ b/include/nana/gui/widgets/tabbar.hpp @@ -0,0 +1,332 @@ +/* + * A Tabbar implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/tabbar.hpp + * @brief: A tabbar contains tab items and toolbox for scrolling, closing, selecting items. + * + */ +#ifndef NANA_GUI_WIDGET_TABBAR_HPP +#define NANA_GUI_WIDGET_TABBAR_HPP +#include "widget.hpp" +#include "../../paint/gadget.hpp" +#include +#include + +namespace nana +{ + template class tabbar; + + template + struct arg_tabbar + { + tabbar & widget; + T & value; + }; + + template + struct arg_tabbar_removed : public arg_tabbar + { + arg_tabbar_removed(tabbar& wdg, T& v) + : arg_tabbar({wdg, v}) + {} + + bool remove = true; + }; + + namespace drawerbase + { + namespace tabbar + { + template + struct tabbar_events + : public general_events + { + typedef T value_type; + + basic_event> added; + basic_event> activated; + basic_event> removed; + }; + + class event_agent_interface + { + public: + virtual ~event_agent_interface() = 0; + virtual void added(std::size_t) = 0; + virtual void activated(std::size_t) = 0; + virtual bool removed(std::size_t) = 0; + }; + + class item_renderer + { + public: + typedef item_renderer item_renderer_type; + typedef nana::paint::graphics & graph_reference; + enum state_t{disable, normal, highlight, press}; + + struct item_t + { + nana::rectangle r; + nana::color_t bgcolor; + nana::color_t fgcolor; + }; + + virtual ~item_renderer() = 0; + virtual void background(graph_reference, const nana::rectangle& r, nana::color_t bgcolor) = 0; + virtual void item(graph_reference, const item_t&, bool active, state_t) = 0; + virtual void close_fly(graph_reference, const nana::rectangle&, bool active, state_t) = 0; + + virtual void add(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void close(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void back(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void next(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void list(graph_reference, const nana::rectangle&, state_t) = 0; + }; + + template + class event_agent + : public event_agent_interface + { + public: + typedef ::nana::arg_tabbar arg_tabbar; + + event_agent(::nana::tabbar& tb, DrawerTrigger & dtr) + : tabbar_(tb), drawer_trigger_(dtr) + {} + + void added(std::size_t pos) override + { + if(pos != npos) + { + drawer_trigger_.at_no_bound_check(pos) = T(); + tabbar_.events().added.emit(arg_tabbar({ tabbar_, tabbar_[pos] })); + } + } + + void activated(std::size_t pos) override + { + if(pos != npos) + tabbar_.events().activated.emit(arg_tabbar({ tabbar_, tabbar_[pos]})); + } + + bool removed(std::size_t pos) override + { + if (pos != npos) + { + ::nana::arg_tabbar_removed arg(tabbar_, tabbar_[pos]); + tabbar_.events().removed.emit(arg); + return arg.remove; + } + return true; + } + private: + ::nana::tabbar & tabbar_; + DrawerTrigger& drawer_trigger_; + }; + + class layouter; + + class trigger + : public drawer_trigger + { + public: + enum toolbox_button_t{ButtonAdd, ButtonScroll, ButtonList, ButtonClose}; + trigger(); + ~trigger(); + void activate(std::size_t); + std::size_t activated() const; + nana::any& at(std::size_t) const; + nana::any& at_no_bound_check(std::size_t) const; + const pat::cloneable & ext_renderer() const; + void ext_renderer(const pat::cloneable&); + void set_event_agent(event_agent_interface*); + void push_back(const nana::string&, const nana::any&); + std::size_t length() const; + bool close_fly(bool); + void relate(size_t, window); + void tab_color(std::size_t, bool is_bgcolor, nana::color_t); + void tab_image(size_t, const nana::paint::image&); + void text(std::size_t, const nana::string&); + nana::string text(std::size_t) const; + bool toolbox_button(toolbox_button_t, bool); + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + private: + layouter * layouter_; + }; + } + }//end namespace drawerbase + /// Analogous to dividers in a notebook or the labels in a file cabinet + template + class tabbar + : public widget_object> + { + typedef drawerbase::tabbar::trigger drawer_trigger_t; + public: + typedef Type value_type; ///< The type of element data which is stored in the tabbar. + typedef drawerbase::tabbar::item_renderer item_renderer; ///< A user-defined item renderer should be derived from this interface. + + struct button_add{}; ///< The type identifies the add button of the tabbar's toolbox. + struct button_scroll{}; ///< The type identifies the scroll button of the tabbar's toolbox. + struct button_list{}; ///< The type identifies the list button of the tabbar's toolbox. + struct button_close{}; ///< The type identifies the close button of the tabbar's toolbox. + + /// A template class identifies the buttons of the tabbars toolbox. Refer to notes for more details. + template + struct button_container + { + typedef meta::fixed_type_set type_set; + }; + + tabbar() + { + evt_agent_.reset(new drawerbase::tabbar::event_agent(*this, this->get_drawer_trigger())); + this->get_drawer_trigger().set_event_agent(evt_agent_.get()); + } + + tabbar(window wd, bool visible) + : tabbar() + { + this->create(wd, rectangle(), visible); + } + + tabbar(window wd, const nana::char_t* text, bool visible) + : tabbar(wd, ::nana::string(text), visible) + { + } + + tabbar(window wd, const nana::string& text, bool visible) + : tabbar() + { + this->create(wd, rectangle(), visible); + this->caption(text); + } + + tabbar(window wd, const rectangle& r = rectangle(), bool visible = true) + : tabbar() + { + this->create(wd, r, visible); + } + + ~tabbar() + { + this->get_drawer_trigger().set_event_agent(nullptr); + } + + value_type & operator[](std::size_t pos) const + { + return static_cast(this->get_drawer_trigger().at_no_bound_check(pos)); + } + + void activate(std::size_t pos) /// Activates a tab specified by i. + { + this->get_drawer_trigger().activate(pos); + } + + std::size_t activated() const + { + return this->get_drawer_trigger().activated(); + } + + value_type & at(std::size_t i) const /// Returns i'th element + { + return static_cast(this->get_drawer_trigger().at(i)); + } + + void close_fly(bool fly) /// Draw or not a close button in each tab. + { + if(this->get_drawer_trigger().close_fly(fly)) + API::refresh_window(this->handle()); + } + + pat::cloneable& ext_renderer() const + { + return this->get_drawer_trigger().ext_renderer(); + } + + void ext_renderer(const pat::cloneable& ir) + { + this->get_drawer_trigger().ext_renderer(ir); + } + + std::size_t length() const /// Returns the number of items. + { + return this->get_drawer_trigger().length(); + } + + void push_back(const nana::string& text) /// Append a new item. + { + auto & t = this->get_drawer_trigger(); + t.push_back(text, value_type()); + API::update_window(*this); + } + + void relate(std::size_t pos, window wd) /// Binds a window to an item specified by pos, if the item is selected, shows the window, otherwise, hides it. + { + this->get_drawer_trigger().relate(pos, wd); + } + + void tab_bgcolor(std::size_t i, nana::color_t color) + { + this->get_drawer_trigger().tab_color(i, true, color); + } + + void tab_fgcolor(std::size_t i, nana::color_t color) + { + this->get_drawer_trigger().tab_color(i, false, color); + } + + void tab_image(std::size_t i, const nana::paint::image& img) + { + this->get_drawer_trigger().tab_image(i, img); + } + /// Sets buttons of the tabbar's toolbox, refer to notes for more details. + template + void toolbox(const button_container&, bool enable) + { + typedef typename button_container::type_set type_set; + auto & tg = this->get_drawer_trigger(); + bool redraw = false; + + if(type_set::template count::value) + redraw |= tg.toolbox_button(tg.ButtonAdd, enable); + + if(type_set::template count::value) + redraw |= tg.toolbox_button(tg.ButtonScroll, enable); + + if(type_set::template count::value) + redraw |= tg.toolbox_button(tg.ButtonList, enable); + + if(type_set::template count::value) + redraw |= tg.toolbox_button(tg.ButtonClose, enable); + + if(redraw) + API::refresh_window(this->handle()); + } + + void text(std::size_t pos, const nana::string& str) /// Sets the title of the specified item, If pos is invalid, the method throws an std::out_of_range object. + { + this->get_drawer_trigger().text(pos, str); + } + + nana::string text(std::size_t pos) const /// Returns a title of a specified item, If pos is invalid, the method trhows a std::out_of_range object. + { + return this->get_drawer_trigger().text(pos); + } + private: + std::unique_ptr > evt_agent_; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp new file mode 100644 index 00000000..8bebeb76 --- /dev/null +++ b/include/nana/gui/widgets/textbox.hpp @@ -0,0 +1,189 @@ +/* + * A Textbox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/textbox.hpp + */ +#ifndef NANA_GUI_WIDGET_TEXTBOX_HPP +#define NANA_GUI_WIDGET_TEXTBOX_HPP +#include +#include "skeletons/textbase_export_interface.hpp" + +namespace nana +{ + class textbox; + + struct arg_textbox + { + textbox& widget; + }; + + namespace widgets + { + namespace skeletons + { + class text_editor; + } + } + + namespace drawerbase + { + namespace textbox + { + struct textbox_events + : public general_events + { + basic_event first_change; + }; + + class event_agent + : public widgets::skeletons::textbase_event_agent_interface + { + public: + event_agent(::nana::textbox& wdg); + void first_change() override; + private: + ::nana::textbox & widget_; + }; + + //class drawer + class drawer + : public drawer_trigger + { + public: + typedef widgets::skeletons::text_editor text_editor; + + drawer(); + text_editor * editor(); + const text_editor * editor() const; + void set_accept(std::function &&); + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void focus(graph_reference, const arg_focus&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void key_press(graph_reference, const arg_keyboard&)override; + void key_char(graph_reference, const arg_keyboard&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void resized(graph_reference, const arg_resized&) override; + void typeface_changed(graph_reference) override; + private: + void _m_text_area(unsigned width, unsigned height); + void _m_draw_border(graph_reference, nana::color_t bgcolor); + private: + widget* widget_; + struct status_type + { + bool has_focus; //Indicates whether it has the keyboard focus + }status_; + + std::function pred_acceptive_; + widgets::skeletons::text_editor * editor_; + std::unique_ptr evt_agent_; + }; + }//end namespace textbox + }//end namespace drawerbase + + /// Allow users to enter and edit text by typing on the keyboard. + class textbox + :public widget_object + { + public: + /// The default constructor without creating the widget. + textbox(); + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param visible specifying the visible after creating. + textbox(window, bool visible); + + /// \brief The construct that creates a widget with a specified text. + /// @param window A handle to the parent window of the widget being created. + /// @param text the text that will be displayed. + /// @param visible specifying the visible after creating. + textbox(window, const nana::string& text, bool visible = true); + + /// \brief The construct that creates a widget with a specified text. + /// @param window A handle to the parent window of the widget being created. + /// @param text the text that will be displayed. + /// @param visible specifying the visible after creating. + textbox(window, const nana::char_t* text, bool visible = true); + + /// \brief The construct that creates a widget. + /// @param window A handle to the parent window of the widget being created. + /// @param rectangle the size and position of the widget in its parent window coordinate. + /// @param visible specifying the visible after creating. + textbox(window, const rectangle& = rectangle(), bool visible = true); + + /// \brief Loads a text file. When attempt to load a unicode encoded text file, be sure the file have a BOM header. + void load(nana::string file); + void store(nana::string file); + void store(nana::string file, nana::unicode encoding); + textbox& reset(nana::string = {}); ///< discard the old text and set a newtext + + /// The file of last store operation. + nana::string filename() const; + + /// Determine whether the text was edited. + bool edited() const; + + /// Reset the edited flag to false manually + textbox& edited_reset(); + + /// Determine whether the changed text has been saved into the file. + bool saved() const; + + /// Read the text from a specified line. It returns true for success. + bool getline(std::size_t line_index, nana::string&) const; + + /// Appends an string. If `at_caret` is `true`, the string is inserted at the position of caret, otherwise, it is appended at end of the textbox. + textbox& append(const nana::string& text, bool at_caret); + + /// Determine wheter the text is line wrapped. + bool line_wrapped() const; + textbox& line_wrapped(bool); + + /// Determine whether the text is multi-line enabled. + bool multi_lines() const; + textbox& multi_lines(bool); + bool editable() const; + textbox& editable(bool); + void set_accept(std::function); + + textbox& tip_string(nana::string); + + /// Set a mask character. Text is displayed as mask character if a mask character is set. This is used for hiding some special text, such as password. + textbox& mask(nana::char_t); + + /// Returns true if some text is selected. + bool selected() const; + + /// Selects/unselects all text. + void select(bool); + + void copy() const; ///< Copies the selected text into shared memory, such as clipboard under Windows. + void paste(); ///< Pastes the text from shared memory. + void del(); + + int to_int() const; + double to_double() const; + textbox& from(int); + textbox& from(double); + protected: + //Overrides widget's virtual functions + ::nana::string _m_caption() const override; + void _m_caption(::nana::string&&) override; + void _m_typeface(const paint::font&) override; + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp new file mode 100644 index 00000000..fd3b43df --- /dev/null +++ b/include/nana/gui/widgets/toolbar.hpp @@ -0,0 +1,102 @@ +/* + * A Toolbar Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/toolbar.hpp + */ + +#ifndef NANA_GUI_WIDGET_TOOLBAR_HPP +#define NANA_GUI_WIDGET_TOOLBAR_HPP + +#include "widget.hpp" +#include + +namespace nana +{ + class toolbar; + + struct arg_toolbar + { + toolbar& widget; + std::size_t button; + }; + + namespace drawerbase + { + namespace toolbar + { + struct toolbar_events + : public general_events + { + basic_event selected; ///< A mouse click on a control button. + basic_event enter; ///< The mouse enters a control button. + basic_event leave; ///< The mouse leaves a control button. + + }; + + struct item_type; + + class drawer + : public drawer_trigger + { + struct drawer_impl_type; + + public: + typedef std::size_t size_type; + + drawer(); + ~drawer(); + + void append(const nana::string&, const nana::paint::image&); + void append(); + bool enable(size_type) const; + bool enable(size_type, bool); + void scale(unsigned); + private: + void refresh(graph_reference) override; + void attached(widget_reference, graph_reference) override; + void detached() override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + private: + size_type _m_which(int x, int y, bool want_if_disabled) const; + void _m_draw_background(nana::color_t); + void _m_draw(); + void _m_owner_sized(const arg_resized&); + private: + void _m_fill_pixels(item_type*, bool force); + private: + ::nana::toolbar* widget_; + ::nana::paint::graphics* graph_; + drawer_impl_type* impl_; + }; + + }//end namespace toolbar + }//end namespace drawerbase + /// Control bar that contains buttons for controlling + class toolbar + : public widget_object + { + public: + typedef std::size_t size_type; ///< A type to count the number of elements. + + toolbar(); + toolbar(window, bool visible); + toolbar(window, const rectangle& = rectangle(), bool visible = true); + + void append(); ///< Adds a separator. + void append(const nana::string& text, const nana::paint::image& img); ///< Adds a control button. + void append(const nana::string& text); ///< Adds a control button. + bool enable(size_type index) const; + void enable(size_type index, bool enable_state); + void scale(unsigned s); ///< Sets the scale of control button. + }; +}//end namespace nana +#endif diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp new file mode 100644 index 00000000..a5235880 --- /dev/null +++ b/include/nana/gui/widgets/treebox.hpp @@ -0,0 +1,440 @@ +/* + * A Tree Box Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/widgets/treebox.hpp + * @brief: + * The treebox organizes the nodes by a key string. + * The treebox would have a vertical scrollbar if the node + * is too many to display. And it does not have a horizontal scrollbar, + * the widget will adjust the node's displaying position for fitting. + */ + +#ifndef NANA_GUI_WIDGETS_TREEBOX_HPP +#define NANA_GUI_WIDGETS_TREEBOX_HPP +#include "widget.hpp" +#include "detail/compset.hpp" +#include +#include "detail/tree_cont.hpp" +#include +#include +#include +#include + +namespace nana +{ + class treebox; + + namespace drawerbase + { + namespace treebox + { + enum class component + { + begin, expender = begin, crook, icon, text, bground, end + }; + + struct node_image_tag + { + nana::paint::image normal; + nana::paint::image hovered; + nana::paint::image expanded; + }; + + struct node_attribute + { + bool has_children; + bool expended; + checkstate checked; + bool selected; + bool mouse_pointed; + nana::paint::image icon_normal; + nana::paint::image icon_hover; + nana::paint::image icon_expanded; + nana::string text; + }; + + typedef widgets::detail::compset compset_interface; + typedef widgets::detail::compset_placer compset_placer_interface; + + class renderer_interface + { + public: + typedef drawerbase::treebox::component component; + typedef ::nana::paint::graphics& graph_reference; + typedef drawerbase::treebox::compset_interface compset_interface; + typedef compset_interface::item_attribute_t item_attribute_t; + typedef compset_interface::comp_attribute_t comp_attribute_t; + + virtual ~renderer_interface() + {} + + virtual void bground(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; + virtual void expander(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; + virtual void crook(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; + virtual void icon(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; + virtual void text(graph_reference, nana::color_t bgcolor, nana::color_t fgcolor, const compset_interface *) const = 0; + }; + + class item_proxy; + + class trigger + :public drawer_trigger + { + template + struct basic_implement; + + class item_renderer; + class item_locator; + + typedef basic_implement implement; + public: + struct treebox_node_type + { + treebox_node_type(); + treebox_node_type(nana::string); + treebox_node_type& operator=(const treebox_node_type&); + + nana::string text; + nana::any value; + bool expanded; + checkstate checked; + nana::string img_idstr; + }; + + struct pseudo_node_type{}; + + typedef widgets::detail::tree_cont tree_cont_type; + typedef tree_cont_type::node_type node_type; + + trigger(); + ~trigger(); + + implement * impl() const; + + void auto_draw(bool); + void checkable(bool); + bool checkable() const; + void check(node_type*, checkstate); + bool draw(); + + const tree_cont_type & tree() const; + tree_cont_type & tree(); + + void renderer(::nana::pat::cloneable&&); + const ::nana::pat::cloneable& renderer() const; + void placer(::nana::pat::cloneable&&); + const ::nana::pat::cloneable& placer() const; + + nana::any & value(node_type*) const; + node_type* insert(node_type*, const nana::string& key, nana::string&&); + node_type* insert(const nana::string& path, nana::string&&); + + bool verify(const void*) const; + bool verify_kinship(node_type* parent, node_type* child) const; + + void remove(node_type*); + node_type * selected() const; + void selected(node_type*); + void set_expand(node_type*, bool); + void set_expand(const nana::string& path, bool); + + //void image(const nana::string& id, const node_image_tag&); + node_image_tag& icon(const nana::string&) const; + void icon_erase(const nana::string&); + void node_icon(node_type*, const nana::string& id); + + unsigned node_width(const node_type*) const; + + bool rename(node_type*, const nana::char_t* key, const nana::char_t* name); + private: + //Overrides drawer_trigger methods + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void dbl_click(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void resized(graph_reference, const arg_resized&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + private: + void _m_deal_adjust(); + private: + implement * const impl_; + }; //end class trigger + + + /// \brief A proxy for accessing the node. The key string is case sensitive. + class item_proxy + : public std::iterator + { + public: + item_proxy() = default; ///< The default constructor creates an end iterator. + + //Undocumented constructor. + item_proxy(trigger*, trigger::node_type*); + + /// Append a child. + item_proxy append(const nana::string& key, nana::string name); + + /// Append a child with a specified value (user object.). + template + item_proxy append(const nana::string& key, nana::string name, const T&t) + { + item_proxy ip = append(key, std::move(name)); + if(false == ip.empty()) + ip.value(t); + return ip; + } + + /// Return true if the proxy does not refer to a node, as an end iterator. + bool empty() const; + + /// \brief Return the distance between the ROOT node and this node. + /// @return only available when emtpy() is false. + std::size_t level() const; + + /// Return the check state + bool checked() const; + + /// Set the check state, and it returns itself. + item_proxy& check(bool); + + /// Return true when the node is expanded \todo change to expanded ?? + bool expanded() const; + + /// Expand/Shrink children of the node, and returns itself. \todo change to expand ?? + item_proxy& expand(bool); + + /// Return true when the node is selected. + bool selected() const; + + /// Select the node, and returns itself.. + item_proxy& select(bool); + + /// Return the icon. + const nana::string& icon() const; + + /// Set the icon, and returns itself.. + item_proxy& icon(const nana::string& id); + + /// Return the text. + const nana::string& text() const; + + /// Set a new key, and returns itself.. + item_proxy& key(const nana::string& s); + + /// Return the key. + const nana::string& key() const; + + /// Set the text, and returns itself. + item_proxy& text(const nana::string&); + + std::size_t size() const; ///< Returns the number of child nodes. + + /// Return the first child of the node. + item_proxy child() const; + + /// Return the owner of the node. + item_proxy owner() const; + + /// Return the sibling of the node. + item_proxy sibling() const; + + /// Return the first child of the node + item_proxy begin() const; + + /// An end node. + item_proxy end() const; + + /// Makes an action for each sub item recursively, returns the item that stops the action where action returns false. + item_proxy visit_recursively(std::function action); + + bool operator==(const nana::string& s) const; ///< Compare the text of node with s. + bool operator==(const char* s ) const; ///< Compare the text of node with s. + bool operator==(const wchar_t* s ) const; ///< Compare the text of node with s. + + /// Behavior of Iterator + item_proxy& operator=(const item_proxy&); + + /// Behavior of Iterator + item_proxy & operator++(); + + /// Behavior of Iterator + item_proxy operator++(int); + + /// Behavior of Iterator + item_proxy& operator*(); + + /// Behavior of Iterator + const item_proxy& operator*() const; + + /// Behavior of Iterator + item_proxy* operator->(); + + /// Behavior of Iterator + const item_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const item_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const item_proxy&) const; + + template + T * value_ptr() const + { + return _m_value().get(); + } + + template + T& value() const + { + T* p = _m_value().get(); + if(nullptr == p) + throw std::runtime_error("treebox::value() Invalid type of value."); + return *p; + } + + template + item_proxy & value(const T& t) + { + _m_value() = t; + return *this; + }; + + template + item_proxy & value(T&& t) + { + _m_value() = std::move(t); + return *this; + }; + + // Undocumentated methods for internal use + trigger::node_type * _m_node() const; + private: + nana::any& _m_value(); + const nana::any& _m_value() const; + private: + trigger * trigger_{nullptr}; + trigger::node_type * node_{nullptr}; + };//end class item_proxy + }//end namespace treebox + }//end namespace drawerbase + + struct arg_treebox + { + treebox& widget; + drawerbase::treebox::item_proxy & item; + bool operated; + }; + + namespace drawerbase + { + namespace treebox + { + struct treebox_events + : public general_events + { + basic_event expanded; + basic_event checked; + basic_event selected; + basic_event hovered; + }; + }//end namespace treebox + }//end namespace drawerbase + + /// Displays a hierarchical list of items, such as the files and directories on a disk. + class treebox + :public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events> + { + public: + /// A type refers to the item and also used to iterate through the node. + typedef drawerbase::treebox::item_proxy item_proxy; + + typedef drawerbase::treebox::node_image_tag node_image_type; + + /// The interface of treebox item renderer + typedef drawerbase::treebox::renderer_interface renderer_interface; + + /// The interface of treebox compset_placer + typedef drawerbase::treebox::compset_placer_interface compset_placer_interface; + + /// The default constructor without creating the widget. + treebox(); + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param visible specifying the visible after creating. + treebox(window wd, bool visible); + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param r the size and position of the widget in its parent window coordinate. + /// @param visible specifying the visible after creating. + treebox(window, const nana::rectangle& = rectangle(), bool visible = true); + + template + treebox & renderer(const ItemRenderer & rd) + { + get_drawer_trigger().renderer(::nana::pat::cloneable(rd)); + return *this; + } + + const nana::pat::cloneable & renderer() const; + + template + treebox & placer(const Placer & r) + { + get_drawer_trigger().placer(::nana::pat::cloneable(r)); + return *this; + } + + const nana::pat::cloneable & placer() const; + + /// \brief Eanble the widget to be draws automatically when it is operated. + /// @param bool whether to enable. + void auto_draw(bool); + + /// \brief Enable the checkbox for each item of the widget. + /// @param bool wheter to enable. + treebox & checkable(bool enable); + + /// Determinte whether the checkbox is enabled. + bool checkable() const; + + treebox& icon(const nana::string& id, const node_image_type& node_img); + + node_image_type& icon(const nana::string& id) const; + + void icon_erase(const nana::string& id); + + item_proxy find(const nana::string& keypath); ///< Find an item though a specified keypath. + + /// Inserts a new node to treebox, but if the keypath exists returns the existing node. + item_proxy insert(const nana::string& path_key, ///< specifies the node hierarchical + nana::string title ///< used for displaying + ); + + /// Inserts a new node to treebox, but if the keypath exists returns the existing node. + item_proxy insert( item_proxy pos, ///< the parent item node + const nana::string& key, ///< specifies the new node + nana::string title ///< used for displaying. + ); + item_proxy erase(item_proxy i); + + void erase(const nana::string& keypath); + + nana::string make_key_path(item_proxy i, const nana::string& splitter) const;/// +#include "../basis.hpp" +#include "../programming_interface.hpp" +#include +#include +#include +#include + +namespace nana +{ + class drawer_trigger; + + /// Abstract class for defining the capacity interface. + class widget + : nana::noncopyable, nana::nonmovable + { + typedef void(*dummy_bool_type)(widget* (*)(const widget&)); + public: + virtual ~widget(); + virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created. + bool empty() const; ///< Determines whether the manipulator is handling a window. + void close(); + + window parent() const; + + nana::string caption() const; + void caption(nana::string); + + template + void i18n(std::string msgid, Args&&... args) + { + _m_caption(nana::internationalization().get(msgid, std::forward(args)...)); + } + + void i18n(i18n_eval); + + void cursor(nana::cursor); + nana::cursor cursor() const; ///< Retrieves the shape of cursor + + void typeface(const paint::font& font); + paint::font typeface() const; + + bool enabled() const; ///< Determines whether the window is enabled for mouse and keyboard input. + void enabled(bool); + + void enable_dropfiles(bool); ///< Enables/Disables a window to accept dropped files. + + void focus(); + bool focused() const; + + void show(); ///< Sets the window visible. + void hide(); ///< Sets the window invisible. + bool visible() const; + + nana::size size() const; + void size(const nana::size&); + + point pos() const; + void move(int x, int y); + void move(const rectangle&); + + void foreground(nana::color_t); + nana::color_t foreground() const; + void background(nana::color_t); + nana::color_t background() const; + + general_events& events() const; + + void umake_event(event_handle eh) const; ///< Deletes an event callback by a handle. + widget& tooltip(const nana::string&); + + operator dummy_bool_type() const; + operator window() const; + protected: + //protected members, a derived class must call this implementation if it overrides an implementation + virtual void _m_complete_creation(); + + virtual general_events& _m_get_general_events() const = 0; + virtual nana::string _m_caption() const; + virtual void _m_caption(nana::string&&); + virtual nana::cursor _m_cursor() const; + virtual void _m_cursor(nana::cursor); + virtual void _m_close(); + virtual bool _m_enabled() const; + virtual void _m_enabled(bool); + virtual bool _m_show(bool); + virtual bool _m_visible() const; + virtual void _m_size(const nana::size&); + virtual void _m_move(int x, int y); + virtual void _m_move(const rectangle&); + + virtual void _m_typeface(const nana::paint::font& font); + virtual nana::paint::font _m_typeface() const; + + virtual void _m_foreground(nana::color_t); + virtual nana::color_t _m_foreground() const; + virtual void _m_background(nana::color_t); + virtual nana::color_t _m_background() const; + }; + + /// Base class of all the classes defined as a widget window. Defaultly a widget_tag + template + class widget_object: public widget + { + protected: + typedef DrawerTrigger drawer_trigger_t; + public: + widget_object() + : events_(std::make_shared()) + {} + + ~widget_object() + { + if(handle_) + API::close_window(handle_); + } + + Events& events() const + { + return *events_; + } + + bool create(window parent_wd, bool visible) ///< Creates a no-size (zero-size) widget. in a widget/root window specified by parent_wd. + { + return create(parent_wd, rectangle(), visible); + } + + bool create(window parent_wd, const rectangle & r = rectangle(), bool visible = true) ///< in a widget/root window specified by parent_wd. + { + if(parent_wd && this->empty()) + { + handle_ = API::dev::create_widget(parent_wd, r, this); + API::dev::set_events(handle_, events_); + API::dev::attach_signal(handle_, *this, &widget_object::signal); + API::dev::attach_drawer(*this, trigger_); + if(visible) + API::show_window(handle_, true); + + this->_m_complete_creation(); + } + return (this->empty() == false); + } + + window handle() const override + { + return handle_; + } + + widget_object& borderless(bool enable) + { + API::widget_borderless(handle_, enable); + return *this; + } + + bool borderless() const + { + return API::widget_borderless(handle_); + } + protected: + DrawerTrigger& get_drawer_trigger() + { + return trigger_; + } + + const DrawerTrigger& get_drawer_trigger() const + { + return trigger_; + } + private: + void signal(detail::signals::code code, const detail::signals& sig) + { + typedef detail::signals::code codes; + switch(code) + { + case codes::caption: + this->_m_caption(sig.info.caption); + break; + case codes::read_caption: + *sig.info.str = this->_m_caption(); + break; + case codes::destroy: + handle_ = nullptr; + break; + default: + break; + } + } + + general_events& _m_get_general_events() const + { + return *events_; + } + private: + window handle_{nullptr}; + DrawerTrigger trigger_; + std::shared_ptr events_; + };//end class widget_object + + /// Base class of all the classes defined as a non-graphics-buffer widget window. The second template parameter DrawerTrigger is always ignored.\see nana::panel + template + class widget_object: public widget + { + protected: + typedef DrawerTrigger drawer_trigger_t; + public: + + widget_object() + : events_(std::make_shared()) + {} + + ~widget_object() + { + if(handle_) + API::close_window(handle_); + } + + Events& events() const + { + return *events_; + } + + bool create(window parent_wd, bool visible) ///< Creates a no-size (zero-size) widget. in a widget/root window specified by parent_wd. + { + return create(parent_wd, rectangle(), visible); + } + + bool create(window parent_wd, const rectangle& r = rectangle(), bool visible = true) ///< in a widget/root window specified by parent_wd. + { + if(parent_wd && this->empty()) + { + handle_ = API::dev::create_lite_widget(parent_wd, r, this); + API::dev::set_events(handle_, events_); + if(visible) + API::show_window(handle_, true); + this->_m_complete_creation(); + } + return (this->empty() == false); + } + + window handle() const + { + return handle_; + } + private: + void signal(detail::signals::code code, const detail::signals& sig) + { + typedef detail::signals::code codes; + switch(code) + { + case codes::caption: + this->_m_caption(sig.info.caption); + break; + case codes::read_caption: + *sig.info.str = this->_m_caption(); + break; + case codes::destroy: + handle_ = nullptr; + break; + default: + break; + } + } + + general_events& _m_get_general_events() const + { + return *events_; + } + private: + window handle_{nullptr}; + std::shared_ptr events_; + };//end class widget_object + + + /// Base class of all the classes defined as a root window. \see nana::form + template + class widget_object: public widget + { + protected: + typedef DrawerTrigger drawer_trigger_t; + public: + + widget_object() + { + handle_ = API::dev::create_window(nullptr, false, API::make_center(300, 150), appearance(), this); + _m_bind_and_attach(); + } + + widget_object(const rectangle& r, const appearance& apr = appearance()) + { + handle_ = API::dev::create_window(nullptr, false, r, apr, this); + _m_bind_and_attach(); + } + + widget_object(window owner, bool nested, const rectangle& r = rectangle(), const appearance& apr = appearance()) + { + handle_ = API::dev::create_window(owner, nested, r, apr, this); + _m_bind_and_attach(); + } + + ~widget_object() + { + if(handle_) + API::close_window(handle_); + } + + Events& events() const + { + return *events_; + } + + void activate() + { + API::activate_window(handle_); + } + + void bring_to_top() + { + API::bring_to_top(handle_); + } + + window handle() const + { + return handle_; + } + + native_window_type native_handle() const + { + return API::root(handle_); + } + + window owner() const + { + return API::get_owner_window(handle_); + } + + void icon(const nana::paint::image& ico) + { + API::window_icon(handle_, ico); + } + + void restore() + { + API::restore_window(handle_); + } + + void zoom(bool ask_for_max) + { + API::zoom_window(handle_, ask_for_max); + } + + bool is_zoomed(bool ask_for_max) const + { + return API::is_window_zoomed(handle_, ask_for_max); + } + protected: + DrawerTrigger& get_drawer_trigger() + { + return trigger_; + } + + const DrawerTrigger& get_drawer_trigger() const + { + return trigger_; + } + private: + void signal(detail::signals::code code, const detail::signals& sig) + { + typedef detail::signals::code codes; + switch(code) + { + case codes::caption: + this->_m_caption(sig.info.caption); + break; + case codes::read_caption: + *sig.info.str = this->_m_caption(); + break; + case codes::destroy: + handle_ = nullptr; + break; + default: + break; + } + } + + void _m_bind_and_attach() + { + events_ = std::make_shared(); + API::dev::set_events(handle_, events_); + API::dev::attach_signal(handle_, *this, &widget_object::signal); + API::dev::attach_drawer(*this, trigger_); + } + + general_events& _m_get_general_events() const + { + return *events_; + } + private: + window handle_; + DrawerTrigger trigger_; + std::shared_ptr events_; + };//end class widget_object + + /// Base class of all the classes defined as a frame window. \see nana::frame + template + class widget_object: public widget{}; + + /// Especialization. Base class of all the classes defined as a frame window. \see nana::frame + template + class widget_object: public widget + { + protected: + typedef int drawer_trigger_t; + public: + widget_object() + : events_(std::make_shared()) + {} + + ~widget_object() + { + if(handle_) + API::close_window(handle_); + } + + Events& events() const + { + return *events_; + } + + bool create(window parent_wd, bool visible) ///< Creates a no-size (zero-size) widget. in a widget/root window specified by parent_wd. + { + return create(parent_wd, rectangle(), visible); + } + /// Creates in a widget/root window specified by parent_wd. + bool create(window parent_wd, const rectangle& r = rectangle(), bool visible = true) + { + if(parent_wd && this->empty()) + { + handle_ = API::dev::create_frame(parent_wd, r, this); + API::dev::set_events(handle_, events_); + API::dev::attach_signal(handle_, *this, &widget_object::signal); + API::show_window(handle_, visible); + this->_m_complete_creation(); + } + return (this->empty() == false); + } + + window handle() const + { + return handle_; + } + private: + virtual drawer_trigger* get_drawer_trigger() + { + return nullptr; + } + + void signal(detail::signals::code code, const detail::signals& sig) + { + typedef detail::signals::code codes; + switch(code) + { + case codes::caption: + this->_m_caption(sig.info.caption); + break; + case codes::read_caption: + *sig.info.str = this->_m_caption(); + break; + case codes::destroy: + handle_ = nullptr; + break; + default: + break; + } + } + + general_events& _m_get_general_events() const + { + return *events_; + } + private: + window handle_{nullptr}; + std::shared_ptr events_; + };//end class widget_object +}//end namespace nana +#endif diff --git a/include/nana/gui/wvl.hpp b/include/nana/gui/wvl.hpp new file mode 100644 index 00000000..a69f350a --- /dev/null +++ b/include/nana/gui/wvl.hpp @@ -0,0 +1,45 @@ +/* + * Nana GUI Library Definition + * Copyright(C) 2003-2013 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/gui/wvl.hpp + * @description: + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_WVL_HPP +#define NANA_GUI_WVL_HPP + +#include "programming_interface.hpp" +#include "widgets/form.hpp" +#include "drawing.hpp" +#include "msgbox.hpp" +#include "../exceptions.hpp" + +namespace nana +{ + template + class form_loader + { + public: + template + Form & operator()(Args &&... args) const + { + Form* res = detail::bedrock::instance().rt_manager.create_form(std::forward(args)...); + if (nullptr == res) + throw nana::bad_window("form_loader.operator(): failed to create a window"); + + if (IsMakeVisible) res->show(); + + return *res; + } + + }; + + void exec(); +}//end namespace nana +#endif diff --git a/include/nana/internationalization.hpp b/include/nana/internationalization.hpp new file mode 100644 index 00000000..4c9942af --- /dev/null +++ b/include/nana/internationalization.hpp @@ -0,0 +1,211 @@ +/* + * An Implementation of i18n + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/internationalization.hpp + */ + +#ifndef NANA_INTERNATIONALIZATION_HPP +#define NANA_INTERNATIONALIZATION_HPP +#include "basic_types.hpp" +#include +#include +#include +#include + +namespace nana +{ + class internationalization + { + friend class i18n_eval; + public: + void load(const std::string& file); + void load_utf8(const std::string& file); + + template + nana::string get(std::string msgid_utf8, Args&&... args) const + { + std::vector arg_strs; + _m_fetch_args(arg_strs, std::forward(args)...); + + nana::string msgstr; + if (_m_get(msgid_utf8, msgstr)) + _m_replace_args(msgstr, &arg_strs); + return msgstr; + } + + nana::string get(std::string msgid_utf8) const; + void set(std::string msgid_utf8, nana::string msgstr); + + template + nana::string operator()(std::string msgid_utf8, Args&&... args) const + { + return get(msgid_utf8, std::forward(args)...); + } + private: + bool _m_get(std::string& msgid, nana::string& msgstr) const; + void _m_replace_args(nana::string& str, std::vector * arg_strs) const; + + void _m_fetch_args(std::vector&) const //Termination of _m_fetch_args + {} + + template + void _m_fetch_args(std::vector& v, Arg&& arg) const + { + std::wstringstream ss; + ss << arg; + v.emplace_back(ss.str()); + } + + template + void _m_fetch_args(std::vector& v, const char* arg, Args&&... args) const + { + std::wstringstream ss; + ss << nana::string(nana::charset(arg)); + v.emplace_back(ss.str()); + + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, const std::string& arg, Args&&... args) const + { + std::wstringstream ss; + ss << nana::string(nana::charset(arg)); + v.emplace_back(ss.str()); + + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, std::string& arg, Args&&... args) const + { + std::wstringstream ss; + ss << nana::string(nana::charset(arg)); + v.emplace_back(ss.str()); + + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, std::string&& arg, Args&&... args) const + { + std::wstringstream ss; + ss << nana::string(nana::charset(arg)); + v.emplace_back(ss.str()); + + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, Arg&& arg, Args&&... args) const + { + std::wstringstream ss; + ss << arg; + v.emplace_back(ss.str()); + + _m_fetch_args(v, std::forward(args)...); + } + };//end class internationalization + + class i18n_eval + { + class eval_arg + { + public: + virtual ~eval_arg() = default; + virtual nana::string eval() const = 0; + virtual std::unique_ptr clone() const = 0; + }; + + class arg_string; + class arg_eval; + + template + class arg_function + { + public: + arg_function(std::function fn) + : fn_(fn) + {} + + nana::string eval() const override + { + std::wstringstream ss; + ss << fn_(); + return ss.str(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new arg_function(*this)); + } + private: + std::function fn_; + }; + public: + i18n_eval() = default; + + template + i18n_eval(std::string msgid_utf8, Args&&... args) + : msgid_(std::move(msgid_utf8)) + { + _m_fetch_args(std::forward(args)...); + } + + i18n_eval(const i18n_eval&); + + //Workaround for VC2013, becuase it can't specified a default explicit move-constructor + i18n_eval(i18n_eval&&); //= default + + i18n_eval& operator=(const i18n_eval&); + i18n_eval& operator=(i18n_eval&& rhs); + + nana::string operator()() const; + private: + void _m_fetch_args(){} //Termination of _m_fetch_args + + template + void _m_fetch_args(Arg&& arg, Args&&... args) + { + _m_add_args(std::forward(arg)); + _m_fetch_args(std::forward(args)...); + } + + template + void _m_add_args(Arg&& arg) + { + std::wstringstream ss; + ss << arg; + _m_add_args(ss.str()); + } + + template + void _m_add_args(std::function fn) + { + args_.emplace_back(new arg_function(fn)); + } + + void _m_add_args(i18n_eval&); + void _m_add_args(const i18n_eval&); + void _m_add_args(i18n_eval&&); + + void _m_add_args(std::string&); + void _m_add_args(const std::string&); + void _m_add_args(std::string&&); + + void _m_add_args(std::wstring&); + void _m_add_args(const std::wstring&); + void _m_add_args(std::wstring&&); + private: + std::string msgid_; + std::vector> args_; + };//end class i18n_eval; +} + +#endif//NANA_I18N_HPP \ No newline at end of file diff --git a/include/nana/key_type.hpp b/include/nana/key_type.hpp new file mode 100644 index 00000000..9550f8df --- /dev/null +++ b/include/nana/key_type.hpp @@ -0,0 +1,123 @@ +/* +* A Key Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/key_type.hpp +*/ +#ifndef NANA_KEY_TYPE_HPP +#define NANA_KEY_TYPE_HPP + +namespace nana +{ + namespace detail + { + class key_interface + { + public: + virtual ~key_interface(){} + + virtual bool same_type(const key_interface*) const = 0; + virtual bool compare(const key_interface*) const = 0; + }; //end class key_interface + + //Use less compare for equal compare + inline bool pred_equal_by_less(const key_interface * left, const key_interface* right) + { + return (left->compare(right) == false) && (right->compare(left) == false); + } + + template + struct type_escape + { + typedef T type; + }; + + template<> + struct type_escape + { + typedef std::string type; + }; + + template<> + struct type_escape + { + typedef std::string type; + }; + + template + struct type_escape + { + typedef std::string type; + }; + + template + struct type_escape + { + typedef std::string type; + }; + + template<> + struct type_escape + { + typedef std::wstring type; + }; + + template<> + struct type_escape + { + typedef std::wstring type; + }; + + template + struct type_escape + { + typedef std::wstring type; + }; + + template + struct type_escape + { + typedef std::wstring type; + }; + } + + template + class key + : public detail::key_interface + { + public: + typedef detail::key_interface key_interface; + typedef T key_type; + + key(const key_type& k) + : key_object_(k) + {} + + key(key_type&& k) + : key_object_(std::move(k)) + { + } + public: + //implement key_interface methods + bool same_type(const key_interface * p) const override + { + return (nullptr != dynamic_cast(p)); + } + + bool compare(const key_interface* p) const override + { + auto rhs = dynamic_cast(p); + return rhs && compare_(key_object_, rhs->key_object_); + } + private: + Compare compare_; + key_type key_object_; + }; +} + +#endif diff --git a/include/nana/paint/detail/image_bmp.hpp b/include/nana/paint/detail/image_bmp.hpp new file mode 100644 index 00000000..a329628a --- /dev/null +++ b/include/nana/paint/detail/image_bmp.hpp @@ -0,0 +1,359 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_BMP_HPP +#define NANA_PAINT_DETAIL_IMAGE_BMP_HPP + +#include "image_impl_interface.hpp" +#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) + { + 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 = 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); + + pixel_rgb_t * 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 pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + + if(info->bmiHeader.biHeight < 0) + { + const unsigned char* s = bits; + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + const unsigned char * s_p = s; + while(d_p != dpend) + { + rgb_quad & rgb = info->bmiColors[*s_p++]; + d_p->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + } + d = dpend; + s += bytes_per_line; + } + } + else + { + const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * const dpend = d_p + info->bmiHeader.biWidth; + const unsigned char * s_p = s; + while(d_p != dpend) + { + rgb_quad & rgb = info->bmiColors[*s_p++]; + d_p->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + } + d = dpend; + s -= bytes_per_line; + } + } + } + else if(4 == info->bmiHeader.biBitCount) + { + const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + if(info->bmiHeader.biHeight < 0) + { + const unsigned char* s = bits; + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * 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->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + ++index; + } + d = dpend; + s += bytes_per_line; + } + } + else + { + const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * 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->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + ++index; + } + d = dpend; + s -= bytes_per_line; + } + } + } + else if(2 == info->bmiHeader.biBitCount) + { + const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + if(info->bmiHeader.biHeight < 0) + { + const unsigned char* s = bits; + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * 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->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + ++index; + } + d = dpend; + s += bytes_per_line; + } + } + else + { + const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * 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->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + ++index; + } + d = dpend; + s -= bytes_per_line; + } + } + } + else if(1 == info->bmiHeader.biBitCount) + { + const pixel_rgb_t * const lend = d + info->bmiHeader.biWidth * height_pixels; + if(info->bmiHeader.biHeight < 0) + { + const unsigned char* s = bits; + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * 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->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + ++index; + } + d = dpend; + s += bytes_per_line; + } + } + else + { + const unsigned char* s = bits + bytes_per_line * (height_pixels - 1); + while(d < lend) + { + pixel_rgb_t * d_p = d; + pixel_rgb_t * 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->u.element.red = rgb.rgbRed; + d_p->u.element.green = rgb.rgbGreen; + d_p->u.element.blue = rgb.rgbBlue; + d_p->u.element.alpha_channel = rgb.rgbReserved; + ++d_p; + ++index; + } + d = dpend; + s -= bytes_per_line; + } + } + } + } + } + } + return (false == pixbuf_.empty()); + } + + bool alpha_channel() const + { + return false; + } + + bool empty() const + { + return pixbuf_.empty(); + } + + void close() + { + pixbuf_.close(); + } + + nana::size size() const + { + return pixbuf_.size(); + } + + void paste(const nana::rectangle& src_r, graph_reference graph, int x, int y) const + { + if(graph && pixbuf_) + pixbuf_.paste(src_r, graph.handle(), x, y); + } + + void stretch(const nana::rectangle& src_r, graph_reference graph, const nana::rectangle& r) const + { + 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/include/nana/paint/detail/image_ico.hpp b/include/nana/paint/detail/image_ico.hpp new file mode 100644 index 00000000..8c66d19b --- /dev/null +++ b/include/nana/paint/detail/image_ico.hpp @@ -0,0 +1,43 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_ICO_HPP +#define NANA_PAINT_DETAIL_IMAGE_ICO_HPP + +#include "image_impl_interface.hpp" + +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); + bool alpha_channel() const; + bool empty() const; + void close(); + nana::size size() const; + virtual void paste(const nana::rectangle& src_r, graph_reference graph, int x, int y) const; + virtual void stretch(const nana::rectangle&, graph_reference graph, const nana::rectangle& r) const; + + 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/include/nana/paint/detail/image_impl_interface.hpp b/include/nana/paint/detail/image_impl_interface.hpp new file mode 100644 index 00000000..b2a7df50 --- /dev/null +++ b/include/nana/paint/detail/image_impl_interface.hpp @@ -0,0 +1,29 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_IMPL_INTERFACE_HPP +#define NANA_PAINT_DETAIL_IMAGE_IMPL_INTERFACE_HPP + +#include "../image.hpp" + +namespace nana{ namespace paint{ + + // class image::image_impl_interface + // the nana::image refers to an object of image::image_impl_interface by nana::refer. Employing nana::refer to refer the image::implement_t object indirectly is used + // for saving the memory that sharing the same image resource with many nana::image objects. + class image::image_impl_interface + : private nana::noncopyable + { + image_impl_interface& operator=(const image_impl_interface& rhs); + public: + typedef nana::paint::graphics& graph_reference; + virtual ~image_impl_interface() = 0; //The destructor is defined in ../image.cpp + virtual bool open(const nana::char_t* filename) = 0; + virtual bool alpha_channel() const = 0; + virtual bool empty() const = 0; + virtual void close() = 0; + virtual nana::size size() const = 0; + virtual void paste(const nana::rectangle& src_r, graph_reference dst, int x, int y) const = 0; + virtual void stretch(const nana::rectangle& src_r, graph_reference dst, const nana::rectangle& r) const = 0; + };//end class image::image_impl_interface +}//end namespace paint +}//end namespace nana + +#endif diff --git a/include/nana/paint/detail/image_png.hpp b/include/nana/paint/detail/image_png.hpp new file mode 100644 index 00000000..ef61df1f --- /dev/null +++ b/include/nana/paint/detail/image_png.hpp @@ -0,0 +1,188 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_PNG_HPP +#define NANA_PAINT_DETAIL_IMAGE_PNG_HPP + +#include "image_impl_interface.hpp" + +//Separate the libpng from the package that system provides. +#if defined(NANA_LIBPNG) + #include +#else + #include +#endif + +#include +#include "../pixel_buffer.hpp" + +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) + { +#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_rgb_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].u.element.red; + p[u].u.element.red = p[u].u.element.blue; + p[u].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_rgb_t * rgb_row_ptr = pixbuf_.raw_ptr(0); + for(int y = 0; y < png_height; ++y) + { + png_bytep png_ptr = row_ptrs[y]; + + pixel_rgb_t * rgb_end = rgb_row_ptr + png_width; + + if(is_alpha_enabled) + { + for(pixel_rgb_t * i = rgb_row_ptr; i < rgb_end; ++i) + { + i->u.element.red = png_ptr[0]; + i->u.element.green = png_ptr[1]; + i->u.element.blue = png_ptr[2]; + i->u.element.alpha_channel = png_ptr[3]; + png_ptr += png_pixel_bytes; + } + } + else + { + for(pixel_rgb_t * i = rgb_row_ptr; i < rgb_end; ++i) + { + i->u.element.red = png_ptr[0]; + i->u.element.green = png_ptr[1]; + i->u.element.blue = png_ptr[2]; + i->u.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 + { + return pixbuf_.alpha_channel(); + } + + virtual bool empty() const + { + return pixbuf_.empty(); + } + + virtual void close() + { + pixbuf_.close(); + } + + virtual nana::size size() const + { + return pixbuf_.size(); + } + + void paste(const nana::rectangle& src_r, graph_reference graph, int x, int y) const + { + pixbuf_.paste(src_r, graph.handle(), x, y); + } + + void stretch(const nana::rectangle& src_r, graph_reference dst, const nana::rectangle& r) const + { + pixbuf_.stretch(src_r, dst.handle(), r); + } + private: + nana::paint::pixel_buffer pixbuf_; + + }; + }//end namespace detail + }//end namespace paint +}//end namespace nana + +#endif diff --git a/include/nana/paint/detail/image_process_provider.hpp b/include/nana/paint/detail/image_process_provider.hpp new file mode 100644 index 00000000..e3d0ca6f --- /dev/null +++ b/include/nana/paint/detail/image_process_provider.hpp @@ -0,0 +1,127 @@ +#ifndef NANA_PAINT_IMAGE_PROCESS_PROVIDER_HPP +#define NANA_PAINT_IMAGE_PROCESS_PROVIDER_HPP +#include +#include +#include +#include + +namespace nana +{ + namespace paint + { + namespace detail + { + class image_process_provider + : nana::noncopyable + { + image_process_provider(); + + struct stretch_tag + { + typedef paint::image_process::stretch_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t* employee; + }stretch_; + + struct alpha_blend_tag + { + typedef paint::image_process::alpha_blend_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }alpha_blend_; + + struct blend_tag + { + typedef paint::image_process::blend_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }blend_; + + struct line_tag + { + typedef paint::image_process::line_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }line_; + + struct blur_tag + { + typedef paint::image_process::blur_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }blur_; + public: + + static image_process_provider & instance(); + + stretch_tag & ref_stretch_tag(); + paint::image_process::stretch_interface * const * stretch() const; + paint::image_process::stretch_interface * ref_stretch(const std::string& name) const; + + alpha_blend_tag & ref_alpha_blend_tag(); + paint::image_process::alpha_blend_interface * const * alpha_blend() const; + paint::image_process::alpha_blend_interface * ref_alpha_blend(const std::string& name) const; + + blend_tag & ref_blend_tag(); + paint::image_process::blend_interface * const * blend() const; + paint::image_process::blend_interface * ref_blend(const std::string& name) const; + + line_tag & ref_line_tag(); + paint::image_process::line_interface * const * line() const; + paint::image_process::line_interface * ref_line(const std::string& name) const; + + blur_tag & ref_blur_tag(); + paint::image_process::blur_interface * const * blur() const; + paint::image_process::blur_interface * ref_blur(const std::string& name) const; + public: + template + void set(Tag & tag, const std::string& name) + { + auto i = tag.table.find(name); + if(i != tag.table.end()) + tag.employee = &(*(i->second)); + } + + //add + //@brief: The add operation is successful if the name does not exist. + // it does not replace the existing object by new object, becuase this + // feature is thread safe and efficiency. + template + void add(Tag & tag, const std::string& name) + { + if(tag.table.count(name) == 0) + { + typedef typename Tag::cloneable_t cloneable_t; + auto & obj = tag.table[name]; + obj = cloneable_t(ImageProcessor()); + if(nullptr == tag.employee) + tag.employee = &(*obj); + } + } + private: + template + typename Tag::interface_t* _m_read(const Tag& tag, const std::string& name) const + { + auto i = tag.table.find(name); + return (i != tag.table.end() ? &(*i->second) : tag.employee); + } + }; + } + } +}//end namespace nana +#endif diff --git a/include/nana/paint/detail/image_processor.hpp b/include/nana/paint/detail/image_processor.hpp new file mode 100644 index 00000000..44129682 --- /dev/null +++ b/include/nana/paint/detail/image_processor.hpp @@ -0,0 +1,676 @@ +/* + * Image Processor Algorithm Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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_processor.hpp + * @brief: This header file implements the algorithms of image processor + * + * DON'T INCLUDE THIS HEADER FILE DIRECTLY TO YOUR SOURCE FILE. + */ + +#ifndef NANA_PAINT_DETAIL_IMAGE_PROCESSOR_HPP +#define NANA_PAINT_DETAIL_IMAGE_PROCESSOR_HPP +#include "../image_process_interface.hpp" +#include +#include +#include + +namespace nana +{ +namespace paint +{ +namespace detail +{ + namespace algorithms + { + class proximal_interoplation + : public image_process::stretch_interface + { + void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& r_src, paint::pixel_buffer & pixbuf, const nana::rectangle& r_dst) const + { + const auto bytes_per_line = s_pixbuf.bytes_per_line(); + + double rate_x = double(r_src.width) / r_dst.width; + double rate_y = double(r_src.height) / r_dst.height; + + pixel_rgb_t * s_raw_pixbuf = s_pixbuf.raw_ptr(0); + + if(s_pixbuf.alpha_channel()) + { + for(std::size_t row = 0; row < r_dst.height; ++row) + { + const pixel_rgb_t * s_line = pixel_at(s_raw_pixbuf, (static_cast(row * rate_y) + r_src.y) * bytes_per_line); + pixel_rgb_t * i = pixbuf.raw_ptr(r_dst.y + row); + + for(std::size_t x = 0; x < r_dst.width; ++x, ++i) + { + const pixel_rgb_t * s = s_line + static_cast(x * rate_x) + r_src.x; + if(0 == s->u.element.alpha_channel) + continue; + + if(s->u.element.alpha_channel != 255) + { + i->u.element.red = unsigned(i->u.element.red * (255 - s->u.element.alpha_channel) + s->u.element.red * s->u.element.alpha_channel) / 255; + i->u.element.green = unsigned(i->u.element.green * (255 - s->u.element.alpha_channel) + s->u.element.green * s->u.element.alpha_channel) / 255; + i->u.element.blue = unsigned(i->u.element.blue * (255 - s->u.element.alpha_channel) + s->u.element.blue * s->u.element.alpha_channel) / 255; + } + else + { + unsigned alpha_chn = i->u.element.alpha_channel; + *i = *s; + i->u.element.alpha_channel = alpha_chn; + } + } + } + } + else + { + for(std::size_t row = 0; row < r_dst.height; ++row) + { + const pixel_rgb_t * s_line = pixel_at(s_raw_pixbuf, (static_cast(row * rate_y) + r_src.y) * bytes_per_line); + pixel_rgb_t * i = pixbuf.raw_ptr(r_dst.y + row); + + for(std::size_t x = 0; x < r_dst.width; ++x, ++i) + *i = s_line[static_cast(x * rate_x) + r_src.x]; + } + } + } + }; + + class bilinear_interoplation + : public image_process::stretch_interface + { + struct x_u_table_tag + { + int x; + int iu; + int iu_minus_coef; + }; + + void process(const paint::pixel_buffer & s_pixbuf, const nana::rectangle& r_src, paint::pixel_buffer & pixbuf, const nana::rectangle& r_dst) const + { + const auto s_bytes_per_line = s_pixbuf.bytes_per_line(); + + const int shift_size = 8; + const std::size_t coef = 1 << shift_size; + const int double_shift_size = shift_size << 1; + + double rate_x = double(r_src.width) / r_dst.width; + double rate_y = double(r_src.height) / r_dst.height; + + const int right_bound = static_cast(r_src.width) - 1 + r_src.x; + + const nana::pixel_rgb_t * s_raw_pixel_buffer = s_pixbuf.raw_ptr(0); + + const int bottom = r_src.y + static_cast(r_src.height - 1); + + x_u_table_tag * x_u_table = new x_u_table_tag[r_dst.width]; + + for(std::size_t x = 0; x < r_dst.width; ++x) + { + double u = (int(x) + 0.5) * rate_x - 0.5; + x_u_table_tag el; + el.x = r_src.x; + if(u < 0) + { + u = 0; + } + else + { + int ipart = static_cast(u); + el.x += ipart; + u -= ipart; + } + el.iu = static_cast(u * coef); + el.iu_minus_coef = coef - el.iu; + x_u_table[x] = el; + } + + const bool is_alpha_channel = s_pixbuf.alpha_channel(); + + for(std::size_t row = 0; row < r_dst.height; ++row) + { + double v = (int(row) + 0.5) * rate_y - 0.5; + int sy = r_src.y; + if(v < 0) + { + v = 0; + } + else + { + int ipart = static_cast(v); + sy += ipart; + v -= ipart; + } + + std::size_t iv = static_cast(v * coef); + const std::size_t iv_minus_coef = coef - iv; + + const nana::pixel_rgb_t * s_line = pixel_at(s_raw_pixel_buffer, sy * s_bytes_per_line); + const nana::pixel_rgb_t * next_s_line = pixel_at(s_line, (sy < bottom ? s_bytes_per_line : 0)); + + nana::pixel_rgb_t col0; + nana::pixel_rgb_t col1; + nana::pixel_rgb_t col2; + nana::pixel_rgb_t col3; + + pixel_rgb_t * i = pixbuf.raw_ptr(row + r_dst.y) + r_dst.x; + + if(is_alpha_channel) + { + for(std::size_t x = 0; x < r_dst.width; ++x, ++i) + { + x_u_table_tag el = x_u_table[x]; + + col0 = s_line[el.x]; + col1 = next_s_line[el.x]; + + if(el.x < right_bound) + { + col2 = s_line[el.x + 1]; + col3 = next_s_line[el.x + 1]; + } + else + { + col2 = col0; + col3 = col1; + } + + std::size_t coef0 = el.iu_minus_coef * iv_minus_coef; + std::size_t coef1 = el.iu_minus_coef * iv; + std::size_t coef2 = el.iu * iv_minus_coef; + std::size_t coef3 = el.iu * iv; + + unsigned alpha_chn = static_cast((coef0 * col0.u.element.alpha_channel + coef1 * col1.u.element.alpha_channel + (coef2 * col2.u.element.alpha_channel + coef3 * col3.u.element.alpha_channel)) >> double_shift_size); + unsigned s_red = static_cast((coef0 * col0.u.element.red + coef1 * col1.u.element.red + (coef2 * col2.u.element.red + coef3 * col3.u.element.red)) >> double_shift_size); + unsigned s_green = static_cast((coef0 * col0.u.element.green + coef1 * col1.u.element.green + (coef2 * col2.u.element.green + coef3 * col3.u.element.green)) >> double_shift_size); + unsigned s_blue = static_cast((coef0 * col0.u.element.blue + coef1 * col1.u.element.blue + (coef2 * col2.u.element.blue + coef3 * col3.u.element.blue)) >> double_shift_size); + + if(alpha_chn) + { + if(alpha_chn != 255) + { + i->u.element.red = unsigned(i->u.element.red * (255 - alpha_chn) + s_red * alpha_chn) / 255; + i->u.element.green = unsigned(i->u.element.green * (255 - alpha_chn) + s_green * alpha_chn) / 255; + i->u.element.blue = unsigned(i->u.element.blue * (255 - alpha_chn) + s_blue * alpha_chn) / 255; + } + else + { + i->u.element.red = s_red; + i->u.element.green = s_green; + i->u.element.blue = s_blue; + } + } + } + } + else + { + for(std::size_t x = 0; x < r_dst.width; ++x, ++i) + { + x_u_table_tag el = x_u_table[x]; + + col0 = s_line[el.x]; + col1 = next_s_line[el.x]; + + if(el.x < right_bound) + { + col2 = s_line[el.x + 1]; + col3 = next_s_line[el.x + 1]; + } + else + { + col2 = col0; + col3 = col1; + } + + std::size_t coef0 = el.iu_minus_coef * iv_minus_coef; + std::size_t coef1 = el.iu_minus_coef * iv; + std::size_t coef2 = el.iu * iv_minus_coef; + std::size_t coef3 = el.iu * iv; + + i->u.element.red = static_cast((coef0 * col0.u.element.red + coef1 * col1.u.element.red + (coef2 * col2.u.element.red + coef3 * col3.u.element.red)) >> double_shift_size); + i->u.element.green = static_cast((coef0 * col0.u.element.green + coef1 * col1.u.element.green + (coef2 * col2.u.element.green + coef3 * col3.u.element.green)) >> double_shift_size); + i->u.element.blue = static_cast((coef0 * col0.u.element.blue + coef1 * col1.u.element.blue + (coef2 * col2.u.element.blue + coef3 * col3.u.element.blue)) >> double_shift_size); + } + } + } + delete [] x_u_table; + } + }; + + //alpha_blend + class alpha_blend + : public image_process::alpha_blend_interface + { + //process + virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const nana::point& d_pos) const + { + nana::pixel_rgb_t * d_rgb = d_pixbuf.at(d_pos); + nana::pixel_rgb_t * s_rgb = s_pixbuf.raw_ptr(s_r.y) + s_r.x; + if(d_rgb && s_rgb) + { + const unsigned rest = s_r.width & 0x3; + const unsigned length_align4 = s_r.width - rest; + + std::size_t d_step_bytes = d_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); + std::size_t s_step_bytes = s_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); + for(unsigned line = 0; line < s_r.height; ++line) + { + pixel_rgb_t* end = d_rgb + length_align4; + for(; d_rgb < end; d_rgb += 4, s_rgb += 4) + { + //0 + if(s_rgb->u.element.alpha_channel) + { + if(s_rgb->u.element.alpha_channel != 255) + { + d_rgb->u.element.red = unsigned(d_rgb->u.element.red * (255 - s_rgb[0].u.element.alpha_channel) + s_rgb[0].u.element.red * s_rgb[0].u.element.alpha_channel) / 255; + d_rgb->u.element.green = unsigned(d_rgb->u.element.green * (255 - s_rgb[0].u.element.alpha_channel) + s_rgb[0].u.element.green * s_rgb[0].u.element.alpha_channel) / 255; + d_rgb->u.element.blue = unsigned(d_rgb->u.element.blue * (255 - s_rgb[0].u.element.alpha_channel) + s_rgb[0].u.element.blue * s_rgb[0].u.element.alpha_channel) / 255; + } + else + *d_rgb = *s_rgb; + } + + //1 + if(s_rgb[1].u.element.alpha_channel) + { + if(s_rgb[1].u.element.alpha_channel != 255) + { + d_rgb[1].u.element.red = unsigned(d_rgb[1].u.element.red * (255 - s_rgb[1].u.element.alpha_channel) + s_rgb[1].u.element.red * s_rgb[1].u.element.alpha_channel) / 255; + d_rgb[1].u.element.green = unsigned(d_rgb[1].u.element.green * (255 - s_rgb[1].u.element.alpha_channel) + s_rgb[1].u.element.green * s_rgb[1].u.element.alpha_channel) / 255; + d_rgb[1].u.element.blue = unsigned(d_rgb[1].u.element.blue * (255 - s_rgb[1].u.element.alpha_channel) + s_rgb[1].u.element.blue * s_rgb[1].u.element.alpha_channel) / 255; + } + else + d_rgb[1] = s_rgb[1]; + } + + //2 + if(s_rgb[2].u.element.alpha_channel) + { + if(s_rgb[2].u.element.alpha_channel != 255) + { + d_rgb[2].u.element.red = unsigned(d_rgb[2].u.element.red * (255 - s_rgb[2].u.element.alpha_channel) + s_rgb[2].u.element.red * s_rgb[2].u.element.alpha_channel) / 255; + d_rgb[2].u.element.green = unsigned(d_rgb[2].u.element.green * (255 - s_rgb[2].u.element.alpha_channel) + s_rgb[2].u.element.green * s_rgb[2].u.element.alpha_channel) / 255; + d_rgb[2].u.element.blue = unsigned(d_rgb[2].u.element.blue * (255 - s_rgb[2].u.element.alpha_channel) + s_rgb[2].u.element.blue * s_rgb[2].u.element.alpha_channel) / 255; + } + else + d_rgb[2] = s_rgb[2]; + } + + //3 + if(s_rgb[3].u.element.alpha_channel) + { + if(s_rgb[3].u.element.alpha_channel != 255) + { + d_rgb[3].u.element.red = unsigned(d_rgb[3].u.element.red * (255 - s_rgb[3].u.element.alpha_channel) + s_rgb[3].u.element.red * s_rgb[3].u.element.alpha_channel) / 255; + d_rgb[3].u.element.green = unsigned(d_rgb[3].u.element.green * (255 - s_rgb[3].u.element.alpha_channel) + s_rgb[3].u.element.green * s_rgb[3].u.element.alpha_channel) / 255; + d_rgb[3].u.element.blue = unsigned(d_rgb[3].u.element.blue * (255 - s_rgb[3].u.element.alpha_channel) + s_rgb[3].u.element.blue * s_rgb[3].u.element.alpha_channel) / 255; + } + else + d_rgb[3] = s_rgb[3]; + } + } + + const pixel_rgb_t * s_end = s_rgb + rest; + for(auto i = s_rgb; i != s_end; ++i) + { + if(i->u.element.alpha_channel) + { + if(i->u.element.alpha_channel != 255) + { + d_rgb[3].u.element.red = unsigned(d_rgb[3].u.element.red * (255 - i->u.element.alpha_channel) + i->u.element.red * i->u.element.alpha_channel) / 255; + d_rgb[3].u.element.green = unsigned(d_rgb[3].u.element.green * (255 - i->u.element.alpha_channel) + i->u.element.green * i->u.element.alpha_channel) / 255; + d_rgb[3].u.element.blue = unsigned(d_rgb[3].u.element.blue * (255 - i->u.element.alpha_channel) + i->u.element.blue * i->u.element.alpha_channel) / 255; + } + else + d_rgb[3] = *i; + } + } + d_rgb = pixel_at(d_rgb, d_step_bytes); + s_rgb = pixel_at(s_rgb, s_step_bytes); + } + } + } + + }; + + //blend + class blend + : public image_process::blend_interface + { + //process + virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const nana::point& d_pos, double fade_rate) const + { + nana::pixel_rgb_t * d_rgb = d_pixbuf.raw_ptr(d_pos.y) + d_pos.x; + nana::pixel_rgb_t * s_rgb = s_pixbuf.raw_ptr(s_r.y) + s_r.x; + + if(d_rgb && s_rgb) + { + unsigned char* tablebuf = detail::alloc_fade_table(fade_rate);//new unsigned char[0x100 * 2]; + unsigned char* d_table = tablebuf; + unsigned char* s_table = d_table + 0x100; + + const unsigned rest = s_r.width & 0x3; + const unsigned length_align4 = s_r.width - rest; + + std::size_t d_step_bytes = d_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); + std::size_t s_step_bytes = s_pixbuf.bytes_per_line() - (s_r.width - rest) * sizeof(pixel_rgb_t); + for(unsigned line = 0; line < s_r.height; ++line) + { + pixel_rgb_t* end = d_rgb + length_align4; + for(; d_rgb < end; d_rgb += 4, s_rgb += 4) + { + //0 + d_rgb[0].u.element.red = unsigned(d_table[d_rgb[0].u.element.red] + s_table[s_rgb[0].u.element.red]); + d_rgb[0].u.element.green = unsigned(d_table[d_rgb[0].u.element.green] + s_table[s_rgb[0].u.element.green]); + d_rgb[0].u.element.blue = unsigned(d_table[d_rgb[0].u.element.blue] + s_table[s_rgb[0].u.element.blue]); + + //1 + d_rgb[1].u.element.red = unsigned(d_table[d_rgb[1].u.element.red] + s_table[s_rgb[1].u.element.red]); + d_rgb[1].u.element.green = unsigned(d_table[d_rgb[1].u.element.green] + s_table[s_rgb[1].u.element.green]); + d_rgb[1].u.element.blue = unsigned(d_table[d_rgb[1].u.element.blue] + s_table[s_rgb[1].u.element.blue]); + + //2 + d_rgb[2].u.element.red = unsigned(d_table[d_rgb[2].u.element.red] + s_table[s_rgb[2].u.element.red]); + d_rgb[2].u.element.green = unsigned(d_table[d_rgb[2].u.element.green] + s_table[s_rgb[2].u.element.green]); + d_rgb[2].u.element.blue = unsigned(d_table[d_rgb[2].u.element.blue] + s_table[s_rgb[2].u.element.blue]); + + //3 + d_rgb[3].u.element.red = unsigned(d_table[d_rgb[3].u.element.red] + s_table[s_rgb[3].u.element.red]); + d_rgb[3].u.element.green = unsigned(d_table[d_rgb[3].u.element.green] + s_table[s_rgb[3].u.element.green]); + d_rgb[3].u.element.blue = unsigned(d_table[d_rgb[3].u.element.blue] + s_table[s_rgb[3].u.element.blue]); + } + + for(unsigned i = 0; i < rest; ++i) + { + d_rgb[i].u.element.red = unsigned(d_table[d_rgb[i].u.element.red] + s_table[s_rgb[i].u.element.red]); + d_rgb[i].u.element.green = unsigned(d_table[d_rgb[i].u.element.green] + s_table[s_rgb[i].u.element.green]); + d_rgb[i].u.element.blue = unsigned(d_table[d_rgb[i].u.element.blue] + s_table[s_rgb[i].u.element.blue]); + } + d_rgb = pixel_at(d_rgb, d_step_bytes); + s_rgb = pixel_at(s_rgb, s_step_bytes); + } + detail::free_fade_table(tablebuf); + } + } + }; + + //class line + class bresenham_line + : public image_process::line_interface + { + virtual void process(paint::pixel_buffer & pixbuf, const nana::point& pos_beg, const nana::point& pos_end, nana::color_t color, double fade_rate) const + { + const std::size_t bytes_pl = pixbuf.bytes_per_line(); + unsigned char * fade_table = nullptr; + nana::pixel_rgb_t rgb_imd; + if(fade_rate != 0.0) + { + fade_table = detail::alloc_fade_table(1 - fade_rate); + rgb_imd.u.color = color; + rgb_imd = detail::fade_color_intermedia(rgb_imd, fade_table); + } + + nana::pixel_rgb_t * i = pixel_at(pixbuf.raw_ptr(0), pos_beg.y * bytes_pl) + pos_beg.x; + + auto delta = pos_end - pos_beg; + + int step_bytes; + if(delta.y < 0) + { + delta.y = -delta.y; + step_bytes = -static_cast(bytes_pl); + } + else + step_bytes = static_cast(bytes_pl); + + if(delta.x == delta.y) + { + step_bytes += sizeof(pixel_rgb_t); + ++delta.x; + + if(fade_table) + { + for(int x = 0; x < delta.x; ++x) + { + *i = detail::fade_color_by_intermedia(*i, rgb_imd, fade_table); + i = pixel_at(i, step_bytes); + } + } + else + { + for(int x = 0; x < delta.x; ++x) + { + i->u.color = color; + i = pixel_at(i, step_bytes); + } + } + } + else + { + int dx_2 = delta.x << 1; + int dy_2 = delta.y << 1; + if(delta.x > delta.y) + { + int error = dy_2 - delta.x; + ++delta.x; //Include the end poing + + if(fade_table) + { + for(int x = 0; x < delta.x; ++x) + { + *i = detail::fade_color_by_intermedia(*i, rgb_imd, fade_table); + if(error >= 0) + { + error -= dx_2; + i = pixel_at(i, step_bytes); + } + error += dy_2; + ++i; + } + } + else + { + for(int x = 0; x < delta.x; ++x) + { + i->u.color = color; + if(error >= 0) + { + error -= dx_2; + i = pixel_at(i, step_bytes); + } + error += dy_2; + ++i; + } + } + } + else + { + int error = dx_2 - delta.y; + ++delta.y; //Include the end point + + if(fade_table) + { + for (int y = 0; y < delta.y; ++y) + { + *i = detail::fade_color_by_intermedia(*i, rgb_imd, fade_table); + if(error >= 0) + { + error -= dy_2; + ++i; + } + error += dx_2; + i = pixel_at(i, step_bytes); + } + } + else + { + for (int y = 0; y < delta.y; ++y) + { + i->u.color = color; + if(error >= 0) + { + error -= dy_2; + ++i; + } + error += dx_2; + i = pixel_at(i, step_bytes); + } + } + } + } + + detail::free_fade_table(fade_table); + } + }; + + class superfast_blur + : public image_process::blur_interface + { + void process(pixel_buffer& pixbuf, const nana::rectangle& area, std::size_t u_radius) const + { + int radius = static_cast(u_radius); + int w = area.width; + int h = area.height; + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = (radius << 1) + 1; + + int large_edge = (w > h ? w : h); + const int div_256 = div * 256; + + std::unique_ptr all_table(new int[(wh << 1) + wh + (large_edge << 1) + div_256]); + + + int * r = all_table.get(); + int * g = r + wh; + int * b = g + wh; + + int * vmin = b + wh; + int * vmax = vmin + large_edge; + + int * dv = vmax + large_edge; + int end_div = div - 1; + for(int i = 0, *dv_block = dv; i < 256; ++i) + { + for(int u = 0; u < end_div; u += 2) + { + dv_block[u] = i; + dv_block[u + 1] = i; + } + dv_block[div - 1] = i; + dv_block += div; + } + + auto linepix = pixbuf.raw_ptr(area.y) + area.x; + + int yi = 0; + for(int y = 0; y < h; ++y) + { + int sum_r = 0, sum_g = 0, sum_b = 0; + if(radius <= wm) + { + for(int i = - radius; i <= radius; ++i) + { + nana::pixel_rgb_t px = linepix[(i > 0 ? i : 0)]; + sum_r += px.u.element.red; + sum_g += px.u.element.green; + sum_b += px.u.element.blue; + } + } + else + { + for(int i = - radius; i <= radius; ++i) + { + nana::pixel_rgb_t px = linepix[std::min(wm, (i > 0 ? i : 0))]; + sum_r += px.u.element.red; + sum_g += px.u.element.green; + sum_b += px.u.element.blue; + } + } + + for(int x = 0; x < w; ++x) + { + r[yi] = dv[sum_r]; + g[yi] = dv[sum_g]; + b[yi] = dv[sum_b]; + + if(0 == y) + { + vmin[x] = std::min(x + radius + 1, wm); + vmax[x] = std::max(x - radius, 0); + } + + nana::pixel_rgb_t p1 = linepix[vmin[x]]; + nana::pixel_rgb_t p2 = linepix[vmax[x]]; + + sum_r += p1.u.element.red - p2.u.element.red; + sum_g += p1.u.element.green - p2.u.element.green; + sum_b += p1.u.element.blue - p2.u.element.blue; + ++yi; + } + linepix = pixbuf.raw_ptr(area.y + y) + area.x; + } + + const int yp_init = -radius * w; + + const std::size_t bytes_pl = pixbuf.bytes_per_line(); + for(int x = 0; x < w; ++x) + { + int sum_r = 0, sum_g = 0, sum_b = 0; + + int yp = yp_init; + for(int i = -radius; i <= radius; ++i) + { + if(yp < 1) + { + sum_r += r[x]; + sum_g += g[x]; + sum_b += b[x]; + } + else + { + int yi = yp + x; + sum_r += r[yi]; + sum_g += g[yi]; + sum_b += b[yi]; + } + yp += w; + } + + linepix = pixbuf.raw_ptr(area.y) + x; + + for(int y = 0; y < h; ++y) + { + linepix->u.color = 0xFF000000 | (dv[sum_r] << 16) | (dv[sum_g] << 8) | dv[sum_b]; + if(x == 0) + { + vmin[y] = std::min(y + radius + 1, hm) * w; + vmax[y] = std::max(y - radius, 0) * w; + } + + int pt1 = x + vmin[y]; + int pt2 = x + vmax[y]; + + sum_r += r[pt1] - r[pt2]; + sum_g += g[pt1] - g[pt2]; + sum_b += b[pt1] - b[pt2]; + + linepix = pixel_at(linepix, bytes_pl); + } + } + } + };//end class superfast_blur + } +} +} +} + +#endif diff --git a/include/nana/paint/detail/native_paint_interface.hpp b/include/nana/paint/detail/native_paint_interface.hpp new file mode 100644 index 00000000..91f47b4d --- /dev/null +++ b/include/nana/paint/detail/native_paint_interface.hpp @@ -0,0 +1,42 @@ +/* + * Platform Implementation + * Copyright(C) 2003-2013 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/native_paint_interface.hpp + */ + +#ifndef NANA_PAINT_DETAIL_PLATFORM_HPP +#define NANA_PAINT_DETAIL_PLATFORM_HPP +#include + +namespace nana +{ +namespace paint +{ +namespace detail +{ + nana::size drawable_size(drawable_type); + + unsigned char * alloc_fade_table(double fade_rate); + void free_fade_table(const unsigned char*); + + //color = bgcolor * fade_rate + fgcolor * (1 - fade_rate); + nana::pixel_rgb_t fade_color(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor, double fade_rate); + nana::pixel_rgb_t fade_color(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor, const unsigned char* const fade_table); + nana::pixel_rgb_t fade_color_intermedia(nana::pixel_rgb_t fgcolor, const unsigned char* fade_table); + nana::pixel_rgb_t fade_color_by_intermedia(nana::pixel_rgb_t bgcolor, nana::pixel_rgb_t fgcolor_intermedia, const unsigned char* const fade_table); + + void blend(drawable_type dw, const nana::rectangle& r, nana::color_t, double fade_rate); + + nana::size raw_text_extent_size(drawable_type, const nana::char_t*, std::size_t len); + nana::size text_extent_size(drawable_type, const nana::char_t*, std::size_t len); + void draw_string(drawable_type, int x, int y, const nana::char_t *, std::size_t len); +}//end namespace detail +}//end namespace paint +}//end namespace nana + +#endif diff --git a/include/nana/paint/gadget.hpp b/include/nana/paint/gadget.hpp new file mode 100644 index 00000000..d7e4e3d7 --- /dev/null +++ b/include/nana/paint/gadget.hpp @@ -0,0 +1,38 @@ +/* + * Graphics Gadget Implementation + * Copyright(C) 2003-2013 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/gadget.hpp + */ + +#ifndef NANA_PAINT_GADGET_HPP +#define NANA_PAINT_GADGET_HPP +#include "graphics.hpp" +#include "image.hpp" +#include + +namespace nana +{ +namespace paint +{ +namespace gadget +{ + struct directions + { + enum t{to_east, to_southeast, to_south, to_southwest, to_west, to_northwest, to_north, to_northeast}; + }; + + void arrow_16_pixels(nana::paint::graphics&, int x, int y, unsigned color, uint32_t style, directions::t direction); + void close_16_pixels(nana::paint::graphics&, int x, int y, uint32_t style, uint32_t color); + void cross(nana::paint::graphics&, int x, int y, uint32_t size, uint32_t thickness, nana::color_t color); + +}//end namespace gadget + +}//end namespace paint +}//end namespace nana + +#endif diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp new file mode 100644 index 00000000..e1ca70b5 --- /dev/null +++ b/include/nana/paint/graphics.hpp @@ -0,0 +1,166 @@ +/* + * Paint Graphics Implementation + * Copyright(C) 2003-2013 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/graphics.hpp + */ + +#ifndef NANA_PAINT_GRAPHICS_HPP +#define NANA_PAINT_GRAPHICS_HPP + +#include "../basic_types.hpp" +#include "../gui/basis.hpp" +#include "pixel_buffer.hpp" +#include + +namespace nana +{ + namespace paint + { + namespace detail + { + struct native_font_signature; + }// end namespace detail + + typedef detail::native_font_signature* native_font_type; + + class font + { + friend class graphics; + public: + font(); + font(drawable_type); + font(const font&); + font(const char_t* name, unsigned size, bool bold = false, bool italic = false, bool underline = false, bool strike_out = false); + ~font(); + bool empty() const; + void make(const char_t* name, unsigned size, bool bold = false, bool italic = false, bool underline = false, bool strike_out = false); + void make_raw(const char_t*, unsigned height, unsigned weight, bool italic, bool underline, bool strike_out); + + void set_default() const; + ::nana::string name() const; + unsigned size() const; + bool bold() const; + unsigned height() const; + unsigned weight() const; + bool italic() const; + native_font_type handle() const; + void release(); + + font& operator=(const font&); + bool operator==(const font&) const; + bool operator!=(const font&) const; + private: + struct impl_type; + impl_type * impl_; + }; + + /// \brief off-screen resource defined as ref-counting, can refer one resource + /// + /// Load a bitmap into a graphics: + /// \code + /// nana::paint::graphics graph; + /// nana::paint::image img("C:\\ABitmap.bmp"); + /// img.paste(graph, 0, 0); //graph may create if it is empty + /// \endcode + class graphics + { + public: + typedef ::nana::native_window_type native_window_type; + + graphics(); + graphics(unsigned width, unsigned height); ///< size in pixel + graphics(const ::nana::size&); ///< size in pixel + graphics(const graphics&); ///< the resource is not copyed, the two graphics objects refer to the *SAME* resource + graphics& operator=(const graphics&); + bool changed() const; ///< Returns true if the graphics object is operated + bool empty() const; ///< Returns true if the graphics object does not refer to any resource. + operator const void*() const; + + drawable_type handle() const; + const void* pixmap() const; + const void* context() const; + void make(unsigned width, unsigned height); ///< Creates a bitmap resource that size is width by height in pixel + void resize(unsigned width, unsigned height); + void typeface(const font&); ///< Selects a specified font type into the graphics object. + font typeface() const; + ::nana::size text_extent_size(const char_t*) const; ///< Computes the width and height of the specified string of text. + ::nana::size text_extent_size(const string&) const; ///< Computes the width and height of the specified string of text. + ::nana::size text_extent_size(const char_t*, std::size_t length) const; ///< Computes the width and height of the specified string of text with the specified length. + ::nana::size text_extent_size(const string&, std::size_t length) const; ///< Computes the width and height of the specified string of text with the specified length. + ::nana::size glyph_extent_size(const char_t*, std::size_t length, std::size_t begin, std::size_t end) const; + ::nana::size glyph_extent_size(const string&, std::size_t length, std::size_t begin, std::size_t end) const; + bool glyph_pixels(const char_t *, std::size_t length, unsigned* pxbuf) const; + ::nana::size bidi_extent_size(const string&) const; + + bool text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const; + + unsigned bidi_string(int x, int y, color_t, const char_t *, std::size_t len); + void string(int x, int y, color_t, const ::nana::string&, std::size_t len); + void string(int x, int y, color_t, const ::nana::string&); + void string(int x, int y, color_t, const char_t*, std::size_t len); + void string(int x, int y, color_t, const char_t*); + + void set_pixel(int x, int y, color_t); + void rectangle(int x, int y, unsigned width, unsigned height, color_t, bool solid); + void rectangle(color_t, bool solid); + void rectangle(const ::nana::rectangle&, color_t, bool solid); + void rectangle_line(const ::nana::rectangle&, color_t left, color_t top, color_t right, color_t bottom); + void round_rectangle(int x, int y, unsigned width, unsigned height, unsigned radius_x, unsigned radius_y, color_t, bool solid, color_t color_if_solid); + void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, color_t, bool solid, color_t color_if_solid); + void shadow_rectangle(const ::nana::rectangle&, color_t beg_color, color_t end_color, bool vertical); + void shadow_rectangle(int x, int y, unsigned width, unsigned height, color_t beg_color, color_t end_color, bool vertical); ///< Draws a width and height rectangle at (x, y) and the color in range of [begin, end] + + void line(int x1, int y1, int x2, int y2, color_t); ///< Draws a line from point (x1, y1) to point (x2, y2) in the specified color. + void line(const point& beg, const point& end, color_t); + void lines(const point* points, std::size_t n_of_points, color_t); + void line_begin(int x, int y); + void line_to(int x, int y, color_t); + + void bitblt(int x, int y, const graphics& source); ///< Transfers the source to the specified point. + void bitblt(const ::nana::rectangle& r_dst, native_window_type src); ///< Transfers the color data corresponding to r_dst from the src window to this graphics. + void bitblt(const ::nana::rectangle& r_dst, native_window_type src, const point& p_src); ///< Transfers the color data corresponding to r_dst from the src window at point p_src to this graphics. + void bitblt(const ::nana::rectangle& r_dst, const graphics& src); ///< Transfers the color data corresponding to r_dst from the src graphics to this graphics. + void bitblt(const ::nana::rectangle& r_dst, const graphics& src, const point& p_src);///< Transfers the color data corresponding to r_dst from the src graphics at point p_src to this graphics. + + void blend(const ::nana::rectangle& s_r, graphics& dst, const point& d_pos, double fade_rate) const;///< blends with the dst object. + void blend(const ::nana::rectangle& r, color_t, double fade_rate); ///< blends the specifed block width the specified color. + + void blur(const ::nana::rectangle& r, std::size_t radius); ///< Blur process. + + void paste(graphics& dst, int x, int y) const; ///< Paste the graphics object into the dest at (x, y) + void paste(native_window_type dst, const ::nana::rectangle&, int sx, int sy) const; ///< Paste the graphics object into a platform-dependent window at (x, y) + void paste(native_window_type dst, int dx, int dy, unsigned width, unsigned height, int sx, int sy) const; + void paste(drawable_type dst, int x, int y) const; + void paste(const ::nana::rectangle& r_src, graphics& dst, int x, int y) const; + void rgb_to_wb(); ///< Transform a color graphics into black&white. + + void stretch(const ::nana::rectangle& src_r, graphics& dst, const ::nana::rectangle& r) const; + void stretch(graphics& dst, const ::nana::rectangle& r) const; + + void flush(); + + unsigned width() const; + unsigned height() const; ///< Returns the height of the off-screen buffer. + ::nana::size size() const; + void setsta(); ///< Clears the status if the graphics object had been changed + void release(); + void save_as_file(const char*); + + static color_t mix(color_t colorX, color_t colorY, double persent); + private: + std::shared_ptr< ::nana::detail::drawable_impl_type> dwptr_; + font font_shadow_; + drawable_type handle_; + ::nana::size size_; + pixel_buffer pxbuf_; + bool changed_; + }; + }//end namespace paint +} //end namespace nana +#endif + diff --git a/include/nana/paint/image.hpp b/include/nana/paint/image.hpp new file mode 100644 index 00000000..d8200293 --- /dev/null +++ b/include/nana/paint/image.hpp @@ -0,0 +1,54 @@ +/* + * Paint Image Implementation + * Copyright(C) 2003-2013 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/image.hpp + * @description: class image is used for load an image file into memory. + */ + +#ifndef NANA_PAINT_IMAGE_HPP +#define NANA_PAINT_IMAGE_HPP + +#include "graphics.hpp" + +namespace nana +{ +namespace paint +{ + /// load a picture file + class image + { + friend class image_accessor; + typedef bool (image::* unspecified_bool_t)() const; + public: + class image_impl_interface; + + image(); + image(const image&); + image(image&&); + image(const nana::char_t* file); + image(const nana::string& filename); + ~image(); + image& operator=(const image& rhs); + image& operator=(image&&); + bool open(const nana::string& filename); + bool empty() const; + operator unspecified_bool_t() const; + void close(); + nana::size size() const; + void paste(graphics& dst, int x, int y) const; + void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst. + void stretch(const nana::rectangle& r_src, graphics& dst, const nana::rectangle& r_dst) const;/// image_ptr_; + };//end class image + +}//end namespace paint +}//end namespace nana + +#endif + diff --git a/include/nana/paint/image_process_interface.hpp b/include/nana/paint/image_process_interface.hpp new file mode 100644 index 00000000..11fc9ed7 --- /dev/null +++ b/include/nana/paint/image_process_interface.hpp @@ -0,0 +1,85 @@ +/* + * Image Processing Interfaces + * Copyright(C) 2003-2013 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/image_process_interface.hpp + */ + +#ifndef NANA_PAINT_IMAGE_PROCESS_INTERFACE_HPP +#define NANA_PAINT_IMAGE_PROCESS_INTERFACE_HPP + +#include +#include + +namespace nana +{ + namespace paint + { /// Image Processing Algorithm Interfaces + namespace image_process + { /// The interface of stretch algorithm. + class stretch_interface + { + public: + virtual ~stretch_interface() = 0; + /// Copies the image from a source rectangle into a destination rectangle, stretching or compressing the image to fit the dimensions of the destination rectangle in destination(d_pixbuf). + virtual void process(const paint::pixel_buffer & s_pixbuf, + const nana::rectangle& source_rectangle, + paint::pixel_buffer & d_pixbuf, + const nana::rectangle& destination_rectangle + ) const = 0; + }; + + class alpha_blend_interface + { + public: + virtual ~alpha_blend_interface() = 0; + virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const point& d_pos) const = 0; + }; + /// The interface of a blend algorithm. + class blend_interface + { + public: + virtual ~blend_interface() = 0; + /// \brief Blends two images with specified area and blend rate. + /// + /// Semantics: \code dest_pixbuf = dest_pixbuf * fade_rate + scr_pixbuf * (1 - fade_rate); \endcode + /// The area is always valid, it is calculated by Nana before passing to the algorithm. So the area could be applied without a check. + virtual void process( const paint::pixel_buffer& src_pixbuf, + const nana::rectangle& src_area, + paint::pixel_buffer& dest_pixbuf, + const nana::point& dest_pos, + double fade_rate ///< blend rate in the range of [0, 1] + ) const = 0; + }; + /// The interface of line algorithm. + class line_interface + { + public: + virtual ~line_interface() = 0; + + /// \brief Draws a line + /// + /// Semantics: \code pixbuf = pixbuf * (1 - fade_rate) + color * fade_rate \endcode + /// The two points are calculated by Nana, they are always valid, and pos_beg.x <= pos_end.x + virtual void process(paint::pixel_buffer & pixbuf, + const nana::point& pos_beg, ///< left point + const nana::point& pos_end, ///< right point + nana::color_t color, + double fade_rate ///< blend rate in the range of [0, 1] If not 0, the line is blended to the pixbuf + ) const = 0; + }; + + class blur_interface + { + public: + virtual ~blur_interface() = 0; + virtual void process(paint::pixel_buffer&, const nana::rectangle& r, std::size_t radius) const = 0; + }; + } + }//end namespace paint +}//end namespace nana +#endif diff --git a/include/nana/paint/image_process_selector.hpp b/include/nana/paint/image_process_selector.hpp new file mode 100644 index 00000000..46a53aea --- /dev/null +++ b/include/nana/paint/image_process_selector.hpp @@ -0,0 +1,71 @@ +#ifndef NANA_PAINT_IMAGE_PROCESS_SELECTOR_HPP +#define NANA_PAINT_IMAGE_PROCESS_SELECTOR_HPP +#include "detail/image_process_provider.hpp" + +namespace nana +{ + namespace paint + { + namespace image_process + { /// Configure the image processing algorithms. + class selector + { + public: + /// Selects an image processor through a specified name. + /*! if users give a non-existing name for choosing an image processor, + the call succeed, but no image processor would be replaced. + */ + void stretch(const std::string& name); + /// Inserts a new user-defined image processor for stretch. + template + void add_stretch(const std::string& name) + { + detail::image_process_provider & p = detail::image_process_provider::instance(); + p.add(p.ref_stretch_tag(), name); + } + + /// Selects an image process through a specified name. + void alpha_blend(const std::string& name); + /// Inserts a new user defined image process for alpha blend. + template + void add_alpha_blend(const std::string& name) + { + detail::image_process_provider& p = detail::image_process_provider::instance(); + p.add(p.ref_alpha_blend_tag(), name); + } + + /// Selects an image processor blend through a specified name. + void blend(const std::string& name); + /// Inserts a new user-defined image processor for blend. + template + void add_blend(const std::string& name) + { + detail::image_process_provider& p = detail::image_process_provider::instance(); + p.add(p.ref_blend_tag(), name); + } + + /// Selects an image processor through a specified name. + void line(const std::string& name); + /// Inserts a new user-defined image processor for line. + template + void add_line(const std::string& name) + { + detail::image_process_provider & p = detail::image_process_provider::instance(); + p.add(p.ref_line_tag(), name); + } + + /// blur - Selects an image procssor through a specified name. + void blur(const std::string& name); + /// Inserts a new user-defined image process for blur. + template + void add_blur(const std::string& name) + { + detail::image_process_provider & p = detail::image_process_provider::instance(); + p.add(p.ref_blur_tag(), name); + } + }; + } + } +} + +#endif diff --git a/include/nana/paint/pixel_buffer.hpp b/include/nana/paint/pixel_buffer.hpp new file mode 100644 index 00000000..9d9dc7fa --- /dev/null +++ b/include/nana/paint/pixel_buffer.hpp @@ -0,0 +1,93 @@ +/* + * Pixel Buffer Implementation + * Copyright(C) 2003-2013 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/pixel_buffer.hpp + */ + +#ifndef NANA_PAINT_PIXEL_BUFFER_HPP +#define NANA_PAINT_PIXEL_BUFFER_HPP + +#include +#include + +namespace nana{ namespace paint +{ + ///@brief Seek a pixel address by using offset bytes + ///@return the specified pixel address + inline pixel_rgb_t * pixel_at(pixel_rgb_t * p, std::size_t bytes) + { + return reinterpret_cast(reinterpret_cast(p) + bytes); + } + + inline const pixel_rgb_t * pixel_at(const pixel_rgb_t * p, std::size_t bytes) + { + return reinterpret_cast(reinterpret_cast(p) + bytes); + } + + class pixel_buffer + { + struct pixel_buffer_storage; + typedef bool (pixel_buffer:: * unspecified_bool_t)() const; + public: + pixel_buffer(); + pixel_buffer(drawable_type, const nana::rectangle& want_rectangle); + pixel_buffer(drawable_type, std::size_t top, std::size_t lines); + pixel_buffer(std::size_t width, std::size_t height); + + ~pixel_buffer(); + + void attach(drawable_type, const nana::rectangle& want_rectangle); + + bool open(drawable_type); + bool open(drawable_type, const nana::rectangle& want_rectangle); + bool open(std::size_t width, std::size_t height); + + void alpha_channel(bool enabled); + bool alpha_channel() const; + + void close(); + + bool empty() const; + + operator unspecified_bool_t() const; + + std::size_t bytes() const; + std::size_t bytes_per_line() const; + nana::size size() const; + + pixel_rgb_t * at(const point& pos) const; + pixel_rgb_t * raw_ptr(std::size_t row) const; + pixel_rgb_t * operator[](std::size_t row) const; + + void put(const unsigned char* rawbits, std::size_t width, std::size_t height, std::size_t bits_per_pixel, std::size_t bytes_per_line, bool is_negative); + + void line(const std::string& name); + void line(const nana::point& pos_beg, const nana::point& pos_end, nana::color_t color, double fade_rate); + + void rectangle(const nana::rectangle&, nana::color_t, double fade_rate, bool solid); + void shadow_rectangle(const nana::rectangle&, nana::color_t beg, nana::color_t end, double fade_rate, bool vertical); + + pixel_rgb_t pixel(int x, int y) const; + void pixel(int x, int y, pixel_rgb_t); + + void paste(drawable_type, int x, int y) const; + void paste(const nana::rectangle& s_r, drawable_type, int x, int y) const; + void paste(native_window_type, int x, int y) const; + void stretch(const std::string& name); + void stretch(const nana::rectangle& s_r, drawable_type, const nana::rectangle& r) const; + void blend(const std::string& name); + void blend(const nana::rectangle& s_r, drawable_type dw_dst, const nana::point& d_pos, double fade_rate) const; + void blur(const nana::rectangle& r, std::size_t radius); + + private: + std::shared_ptr storage_; + }; +}//end namespace paint +}//end namespace nana + +#endif diff --git a/include/nana/paint/text_renderer.hpp b/include/nana/paint/text_renderer.hpp new file mode 100644 index 00000000..7f8ce910 --- /dev/null +++ b/include/nana/paint/text_renderer.hpp @@ -0,0 +1,28 @@ +#ifndef NANA_PAINT_TEXT_RENDERER_HPP +#define NANA_PAINT_TEXT_RENDERER_HPP +#include + +namespace nana +{ + namespace paint + { + class text_renderer + { + public: + typedef graphics & graph_reference; + + text_renderer(graph_reference graph, align = align::left); + + void render(int x, int y, nana::color_t, const nana::char_t*, std::size_t len); + void render(int x, int y, nana::color_t, const nana::char_t*, std::size_t len, unsigned restricted_pixels, bool omitted); + + void render(int x, int y, nana::color_t, const nana::char_t*, std::size_t len, unsigned restricted_pixels); + nana::size extent_size(int x, int y, const nana::char_t*, std::size_t len, unsigned restricted_pixels) const; + private: + graph_reference graph_; + align text_align_; + }; + } +} + +#endif diff --git a/include/nana/pat/cloneable.hpp b/include/nana/pat/cloneable.hpp new file mode 100644 index 00000000..281c36f2 --- /dev/null +++ b/include/nana/pat/cloneable.hpp @@ -0,0 +1,216 @@ +/* +* A Generic Cloneable Pattern Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/pat/cloneable.hpp +* @description: A generic easy-to-use cloneable pattern implementation +*/ +#ifndef NANA_PAT_CLONEABLE_HPP +#define NANA_PAT_CLONEABLE_HPP + +#include +#include +#include + +namespace nana{ namespace pat{ + + namespace detail + { + template + class cloneable_interface + { + public: + typedef T interface_t; + typedef cloneable_interface cloneable_t; + virtual ~cloneable_interface() = default; + virtual interface_t& refer() = 0; + virtual const interface_t& refer() const = 0; + virtual cloneable_t* clone() const = 0; + virtual void self_delete() const = 0; + }; + + + template + class cloneable_wrapper + : public cloneable_interface + { + public: + typedef T value_t; + typedef typename cloneable_interface::interface_t interface_t; + + cloneable_wrapper() + {} + + cloneable_wrapper(const value_t& obj) + :object_(obj) + {} + + cloneable_wrapper(value_t&& rv) + :object_(std::move(rv)) + {} + + template + cloneable_wrapper(const U& u) + : object_(u) + {} + + template + cloneable_wrapper(U& u) + :object_(u) + {} + + virtual interface_t& refer() override + { + return object_; + } + + virtual const interface_t& refer() const override + { + return object_; + } + + virtual cloneable_interface* clone() const override + { + return (new cloneable_wrapper(object_)); + } + + virtual void self_delete() const override + { + (delete this); + } + private: + value_t object_; + }; + + }//end namespace detail + + template + class cloneable + { + using base_t = Base; + using interface_t = detail::cloneable_interface < base_t > ; + + using const_base_ptr = typename std::conditional::type; + using const_base_ref = typename std::conditional::type; + + struct deleter + { + void operator()(interface_t * p) + { + if(p) + p->self_delete(); + } + }; + + struct inner_bool + { + int true_stand; + }; + + typedef int inner_bool::* operator_bool_t; + + template + struct member_enabled + : public std::enable_if<(!std::is_base_of::type>::value) && std::is_base_of::type>::value, int> + {}; + public: + cloneable() = default; + + cloneable(std::nullptr_t){} + + template::type* = nullptr> + cloneable(T&& t) + : cwrapper_(new detail::cloneable_wrapper::type>::type, base_t>(std::forward(t)), deleter()), + fast_ptr_(&(cwrapper_->refer())) + {} + + cloneable(const cloneable& r) + { + if(r.cwrapper_) + { + cwrapper_ = std::shared_ptr(r.cwrapper_->clone(), deleter()); + fast_ptr_ = &(cwrapper_->refer()); + } + } + + cloneable(cloneable && r) + : cwrapper_(std::move(r.cwrapper_)), + fast_ptr_(r.fast_ptr_) + { + r.fast_ptr_ = nullptr; + } + + cloneable & operator=(const cloneable& r) + { + if((this != &r) && r.cwrapper_) + { + cwrapper_ = std::shared_ptr(r.cwrapper_->clone(), deleter()); + fast_ptr_ = &(cwrapper_->refer()); + } + return *this; + } + + cloneable & operator=(cloneable&& r) + { + if(this != &r) + { + cwrapper_ = r.cwrapper_; + fast_ptr_ = r.fast_ptr_; + + r.cwrapper_.reset(); + r.fast_ptr_ = nullptr; + } + return *this; + } + + base_t& operator*() + { + return *fast_ptr_; + } + + const_base_ref operator*() const + { + return *fast_ptr_; + } + + base_t * operator->() + { + return fast_ptr_; + } + + const_base_ptr operator->() const + { + return fast_ptr_; + } + + base_t * get() const + { + return fast_ptr_; + } + + void reset() + { + fast_ptr_ = nullptr; + cwrapper_.reset(); + } + + operator operator_bool_t() const volatile + { + return (fast_ptr_ ? &inner_bool::true_stand : nullptr); + } + private: + std::shared_ptr cwrapper_; + base_t * fast_ptr_{nullptr}; + }; + + template + using mutable_cloneable = cloneable < T, true > ; +}//end namespace pat +}//end namespace nana + +#endif diff --git a/include/nana/std_condition_variable.hpp b/include/nana/std_condition_variable.hpp new file mode 100644 index 00000000..72399b59 --- /dev/null +++ b/include/nana/std_condition_variable.hpp @@ -0,0 +1,12 @@ +#ifndef NANA_STD_CONDITION_VARIABLE_HPP +#define NANA_STD_CONDITION_VARIABLE_HPP +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) +#include +namespace std +{ + typedef boost::condition_variable condition_variable; +} +#endif +#endif // NANA_STD_CONDITION_VARIABLE_HPP diff --git a/include/nana/std_mutex.hpp b/include/nana/std_mutex.hpp new file mode 100644 index 00000000..9fdebfc6 --- /dev/null +++ b/include/nana/std_mutex.hpp @@ -0,0 +1,22 @@ +#ifndef NANA_STD_MUTEX_HPP +#define NANA_STD_MUTEX_HPP +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) +#include +#include +#include + +namespace std +{ + template + using lock_guard = boost::lock_guard; + + template + using unique_lock = boost::unique_lock; + + typedef boost::mutex mutex; + typedef boost::recursive_mutex recursive_mutex; +} +#endif +#endif // NANA_STD_MUTEX_HPP diff --git a/include/nana/std_thread.hpp b/include/nana/std_thread.hpp new file mode 100644 index 00000000..d6d88b18 --- /dev/null +++ b/include/nana/std_thread.hpp @@ -0,0 +1,13 @@ +#ifndef NANA_STD_THREAD_HPP +#define NANA_STD_THREAD_HPP +#include + +#if defined(NANA_MINGW) +#include +namespace std +{ + typedef boost::thread thread; +} +#endif + +#endif // NANA_STD_THREAD_HPP diff --git a/include/nana/system/dataexch.hpp b/include/nana/system/dataexch.hpp new file mode 100644 index 00000000..a730accb --- /dev/null +++ b/include/nana/system/dataexch.hpp @@ -0,0 +1,38 @@ +/* + * Data Exchanger Implementation + * Copyright(C) 2003-2013 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/system/dataexch.hpp + * @description: An implementation of a data exchange mechanism through Windows Clipboard, X11 Selection. + */ + +#ifndef NANA_SYSTEM_DATAEXCH_HPP +#define NANA_SYSTEM_DATAEXCH_HPP +#include + +namespace nana{ namespace system{ + /// a data exchange mechanism through Windows Clipboard, X11 Selection. + class dataexch + { + public: + struct format + { + enum{ text, unicode, pixmap, end}; + }; + + void set(const nana::char_t* text); + void set(const nana::string& text); + void get(nana::string& str); + private: + bool _m_set(unsigned type, const void* buf, std::size_t size); + void* _m_get(unsigned type, size_t& size); + }; + +}//end namespace system +}//end namespace nana + +#endif diff --git a/include/nana/system/platform.hpp b/include/nana/system/platform.hpp new file mode 100644 index 00000000..fd74f757 --- /dev/null +++ b/include/nana/system/platform.hpp @@ -0,0 +1,46 @@ +/* + * A platform API implementation + * Copyright(C) 2003-2013 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/system/platform.hpp + * @description: + * this implements some API for platform-independent programming + */ + +#ifndef NANA_SYSTEM_PLATFORM_HPP +#define NANA_SYSTEM_PLATFORM_HPP +#include + +namespace nana +{ +namespace system +{ + //sleep + //@brief: suspend current thread for a specified milliseconds. + //its precision is depended on hardware. + void sleep(unsigned milliseconds); + + //this_thread_id + //@brief: get the identifier of calling thread. + unsigned long this_thread_id(); + + //timestamp + //@brief: it retrieves the timestamp at the time the function is called. + // it is easy for get the number of milliseconds between calls. + unsigned long timestamp(); + + //get_async_mouse_state + //@brief: it determines whether a mouse button was pressed at the time the function is called. + bool get_async_mouse_state(int button); + + //open an url through a default browser + void open_url(const nana::string& url); + +}//end namespace system +}//end namespace nana + +#endif diff --git a/include/nana/system/shared_wrapper.hpp b/include/nana/system/shared_wrapper.hpp new file mode 100644 index 00000000..78b99618 --- /dev/null +++ b/include/nana/system/shared_wrapper.hpp @@ -0,0 +1,100 @@ +/* + * Operation System Shared Linkage Library Wrapper Implementation + * Copyright(C) 2003 Jinhao + * + * 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/system/shared_wrapper.hpp + * @description: + */ +#ifndef NANA_SYSTEM_SHARED_WRAPPER_HPP +#define NANA_SYSTEM_SHARED_WRAPPER_HPP + +#include +#include +#include + + +namespace nana +{ +namespace system +{ + + namespace detail + { + namespace shared_helper + { + + typedef void* module_t; + void* symbols(module_t handle, const char* symbol); + + }; //end struct shared_helper + }//end namespace detail + + class shared_wrapper + { + typedef detail::shared_helper::module_t module_t; + + + template + struct function_ptr + { + typedef typename std::conditional::value, + Function*, + typename std::conditional::value && std::is_pointer::value, Function, int>::type + >::type type; + }; + + struct impl_type + { + module_t handle; + std::string symbol; + void* proc_address; + + impl_type(); + }; + public: + shared_wrapper(); + shared_wrapper(const char* filename); + ~shared_wrapper(); + + bool open(const char* filename); + void close(); + bool empty() const; + + template + typename function_ptr::type symbols(const char* symbol) + { + typedef typename function_ptr::type fptr_type; + + if(nana::traits::is_function_pointer::value == false) + throw nana::bad_error("shared_wrapper::symbols, template<_Function> is not a function type or a function pointer type"); + + if(symbol == 0) + throw nana::bad_handle("shared_wrapper::symbols, symbol is null string"); + + if(impl_.handle == 0) + throw nana::bad_handle("shared_wrapper::symbols, empty handle"); + + if(impl_.symbol != symbol) + { + void *result = detail::shared_helper::symbols(impl_.handle, symbol); + if(result == 0) + throw nana::bad_handle("shared_wrapper::symbols, empty proc address"); + + impl_.proc_address = result; + impl_.symbol = symbol; + } + return (fptr_type)(this->impl_.proc_address); + } + + private: + impl_type impl_; + }; +}//end namespace system +}//end namespace nana + +#endif + diff --git a/include/nana/system/timepiece.hpp b/include/nana/system/timepiece.hpp new file mode 100644 index 00000000..fe188f45 --- /dev/null +++ b/include/nana/system/timepiece.hpp @@ -0,0 +1,38 @@ +/* + * Timepiece Implementation + * Copyright(C) 2003-2013 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/system/timepiece.hpp + * @description: a time counter + */ + +#ifndef NANA_SYSTEM_TIMEPIECE_HPP +#define NANA_SYSTEM_TIMEPIECE_HPP + +namespace nana +{ +namespace system +{ /// used for measuring and signaling the end of time intervals. + class timepiece + { + public: + timepiece(); + timepiece(const volatile timepiece&); + ~timepiece(); + timepiece & operator=(const volatile timepiece &); + void start() volatile; ///< Set the begin time. + double calc() const volatile; ///< Get the intervals from the begin time. + private: + struct impl_t; + impl_t * impl_; + }; + +}//end namespace system +}//end namespace nana + +#endif + diff --git a/include/nana/threads/pool.hpp b/include/nana/threads/pool.hpp new file mode 100644 index 00000000..410a4b01 --- /dev/null +++ b/include/nana/threads/pool.hpp @@ -0,0 +1,123 @@ +/* + * A Thread Pool Implementation + * Copyright(C) 2003-2013 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/threads/pool.hpp + */ + +#ifndef NANA_THREADS_POOL_HPP +#define NANA_THREADS_POOL_HPP + +#include +#include +#include + + +namespace nana{ + /// Some mutex classes for synchronizing. +namespace threads +{ /// A thread pool manages a group threads for a large number of tasks processing. + class pool + { + struct task + { + enum t{general, signal}; + + const t kind; + + task(t); + virtual ~task() = 0; + virtual void run() = 0; + }; + + template + struct task_wrapper + : task + { + typedef Function function_type; + function_type taskobj; + + task_wrapper(const function_type& f) + : task(task::general), taskobj(f) + {} + + void run() + { + taskobj(); + } + }; + + struct task_signal; + class impl; + public: + pool(); ///< Creates a group of threads. + pool(std::size_t thread_number); ///< Creates a number of threads specifed by thread_number. + ~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks. + + template + void push(const Function& f) + { + task * taskptr = nullptr; + + try + { + taskptr = new task_wrapper::value, Function*, Function>::type>(f); + _m_push(taskptr); + } + catch(std::bad_alloc&) + { + delete taskptr; + } + } + + void signal(); ///< Make a signal that will be triggered when the tasks which are pushed before it are finished. + void wait_for_signal(); ///< Waits for a signal until the signal processed. + void wait_for_finished(); + private: + void _m_push(task* task_ptr); + private: + impl * impl_; + };//end class pool + + /// Manages a group threads for a large number of tasks processing. + template + class pool_pusher + { + public: + /// same as Function if Function is not a function prototype, otherwise value_type is a pointer type of function + typedef typename std::conditional::value, Function*, Function>::type value_type; + + pool_pusher(pool& pobj, value_type fn) + :pobj_(pobj), value_(fn) + {} + + void operator()() const + { + pobj_.push(value_); + } + private: + pool & pobj_; + value_type value_; + }; + + template + pool_pusher pool_push(pool& pobj, const Function& fn) + { + return pool_pusher(pobj, fn); + } + + template + pool_pusher > pool_push(pool& pobj, Class& obj, void(Concept::*mf)()) + { + return pool_pusher >(pobj, std::bind(mf, &obj)); + } + +}//end namespace threads +}//end namespace nana +#endif + diff --git a/include/nana/traits.hpp b/include/nana/traits.hpp new file mode 100644 index 00000000..d1c5c56e --- /dev/null +++ b/include/nana/traits.hpp @@ -0,0 +1,539 @@ +/* + * Traits Implementation + * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * + * @file: nana/traits.hpp + */ + +#ifndef NANA_TRAITS_HPP +#define NANA_TRAITS_HPP +#include + +namespace nana +{ + class null_type{}; + + //The class noncopyable and nonmovable will be deprecated while the compiler + //supports the deleted functions + struct noncopyable + { + noncopyable(const noncopyable&) = delete; + noncopyable& operator=(const noncopyable&) = delete; + noncopyable(); + }; + + struct nonmovable + { + nonmovable(nonmovable&&) = delete; + nonmovable& operator=(nonmovable&&) = delete; + nonmovable(); + }; + + namespace traits + { + //traits types for const-volatile specifier + + struct no_specifier{}; + struct const_specifier{}; + struct volatile_specifier{}; + struct const_volatile_specifier{}; + + template + struct cv_specifier + { + typedef no_specifier value_type; + }; + + template + struct cv_specifier + { + typedef const_specifier value_type; + }; + + template + struct cv_specifier + { + typedef volatile_specifier value_type; + }; + + template + struct cv_specifier + { + typedef const_volatile_specifier value_type; + }; + + template + struct is_function_pointer + : public std::integral_constant::value && std::is_function::type>::value> + {}; + + //The traits of pointer to member function + template + struct mfptr_traits + { + typedef void function(); + typedef void return_type; + typedef void concept_type; + enum{parameter = 0}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef return_type function(); + enum{parameter = 0}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef return_type function(); + enum{parameter = 0}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef return_type function(); + enum{parameter = 0}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef return_type function(); + enum{parameter = 0}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P param0_type; + typedef return_type function(param0_type); + enum{parameter = 1}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P param0_type; + typedef return_type function(param0_type); + enum{parameter = 1}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P param0_type; + typedef return_type function(param0_type); + enum{parameter = 1}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef return_type function(param0_type, param1_type); + enum{parameter = 2}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef return_type function(param0_type, param1_type); + enum{parameter = 2}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef return_type function(param0_type, param1_type); + enum{parameter = 2}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef return_type function(param0_type, param1_type, param2_type); + enum{parameter =3}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef return_type function(param0_type, param1_type, param2_type); + enum{parameter =3}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef return_type function(param0_type, param1_type, param2_type); + enum{parameter =3}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef return_type function(param0_type, param1_type, param2_type); + enum{parameter =3}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type); + enum{parameter = 4}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type); + enum{parameter = 4}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type); + enum{parameter = 4}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type); + enum{parameter = 4}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef P4 param4_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type, param4_type); + enum{parameter = 5}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef P4 param4_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type, param4_type); + enum{parameter = 5}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef P4 param4_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type, param4_type); + enum{parameter = 5}; + }; + + template + struct mfptr_traits + { + typedef Concept concept_type; + typedef R return_type; + typedef P0 param0_type; + typedef P1 param1_type; + typedef P2 param2_type; + typedef P3 param3_type; + typedef P4 param4_type; + typedef return_type function(param0_type, param1_type, param2_type, param3_type, param4_type); + enum{parameter = 5}; + }; + + + + template + struct make_mf + { + typedef int type; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(); + }; + + template + struct make_mf + { + typedef R(Concept::*type)() const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)() volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)() const volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0); + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0) const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0) volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0) const volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1); + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1) const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1) volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1) const volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2); + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2) const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2) volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2) const volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3); + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3) const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3) volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3) const volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4); + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4) const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4) volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4) const volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4, P5); + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4, P5) const; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4, P5) volatile; + }; + + template + struct make_mf + { + typedef R(Concept::*type)(P0, P1, P2, P3, P4, P5) const volatile; + }; + }//end namespace traits + + namespace meta + { + template< typename Param0 = null_type, typename Param1 = null_type, + typename Param2 = null_type, typename Param3 = null_type, + typename Param4 = null_type, typename Param5 = null_type, + typename Param6 = null_type, typename Param7 = null_type, + typename Param8 = null_type, typename Param9 = null_type> + struct fixed_type_set + { + template + struct count + { + enum{value = std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value}; + }; + }; + }//end namespace meta +}//end namespace nana + +#endif diff --git a/include/nana/unicode_bidi.hpp b/include/nana/unicode_bidi.hpp new file mode 100644 index 00000000..acd2b057 --- /dev/null +++ b/include/nana/unicode_bidi.hpp @@ -0,0 +1,75 @@ +#ifndef NANA_UNICODE_BIDI_HPP +#define NANA_UNICODE_BIDI_HPP +#include + +namespace nana +{ + class unicode_bidi + { + public: + typedef wchar_t char_type; + + enum class directional_override_status + { + neutral, right_to_left, left_to_right + }; + + enum class bidi_char + { + L, LRE, LRO, R, AL, RLE, RLO, + PDF = 0x1000, EN, ES, ET, AN, CS, NSM, BN, + B = 0x2000, S, WS, ON + }; + + enum class bidi_category + { + strong, weak = 0x1000, neutral = 0x2000 + }; + + const static char_type LRE = 0x202A; + const static char_type RLE = 0x202B; + const static char_type PDF = 0x202C; + const static char_type LRO = 0x202D; + const static char_type RLO = 0x202E; + const static char_type LRM = 0x200E; + const static char_type RLM = 0x200F; + + struct remember + { + unsigned level; + directional_override_status directional_override; + }; + + struct entity + { + const wchar_t * begin, * end; + bidi_char bidi_char_type; + unsigned level; + }; + + void linestr(const char_type*, std::size_t len, std::vector & reordered); + private: + static unsigned _m_paragraph_level(const char_type * begin, const char_type * end); + + void _m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char); + + std::vector::iterator _m_search_first_character(); + + bidi_char _m_eor(std::vector::iterator); + + void _m_resolve_weak_types(); + void _m_resolve_neutral_types(); + void _m_resolve_implicit_levels(); + void _m_reordering_resolved_levels(const char_type*, std::vector & reordered); + static bidi_category _m_bidi_category(bidi_char); + static bidi_char _m_char_dir(char_type); + private: + void _m_output_levels() const; + void _m_output_bidi_char() const; + private: + std::vector levels_; + }; + +} + +#endif diff --git a/source/any.cpp b/source/any.cpp new file mode 100644 index 00000000..4858d96b --- /dev/null +++ b/source/any.cpp @@ -0,0 +1,70 @@ +#include + + +namespace nana +{ + + //class any + //struct super_type + any::super_type::~super_type(){} + + any::super_type& any::super_type::operator=(const super_type &rhs) + { + return assign(rhs); + } + //end struct super_type + + any::any() + :super_(nullptr) + {} + + any::any(const any& rhs) + :super_(rhs.super_ ? rhs.super_->clone() : nullptr) + {} + + any::any(any&& r) + :super_(r.super_) + { + r.super_ = nullptr; + } + + any::~any() + { + delete super_; + } + + any& any::operator=(const any& rhs) + { + if(this != &rhs) + { + delete super_; + super_ = (rhs.super_ ? rhs.super_->clone() : nullptr); + } + return *this; + } + + any& any::operator=(any&& r) + { + if(this != &r) + { + delete super_; + super_ = r.super_; + r.super_ = nullptr; + } + return *this; + } + + bool any::same(const any &rhs) const + { + if(this != &rhs) + { + if(super_ && rhs.super_) + return super_->same(*rhs.super_); + else if(super_ || rhs.super_) + return false; + } + return true; + } + //end class any +}//end namespace nana + diff --git a/source/audio/detail/audio_device.cpp b/source/audio/detail/audio_device.cpp new file mode 100644 index 00000000..c2b1f72d --- /dev/null +++ b/source/audio/detail/audio_device.cpp @@ -0,0 +1,237 @@ +#include +#include + +#if defined(NANA_LINUX) + #include + #include + #include + #include +#endif + +namespace nana{namespace audio +{ + namespace detail + { +#if defined(NANA_WINDOWS) + class wave_native + { + typedef MMRESULT (__stdcall *out_open_t)(LPHWAVEOUT, UINT_PTR, LPWAVEFORMATEX, DWORD_PTR, DWORD_PTR, DWORD); + typedef MMRESULT (__stdcall *out_close_t)(HWAVEOUT); + typedef MMRESULT (__stdcall *out_op_header_t)(HWAVEOUT, LPWAVEHDR, UINT); + public: + out_open_t out_open; + out_close_t out_close; + out_op_header_t out_write; + out_op_header_t out_prepare; + out_op_header_t out_unprepare; + + wave_native() + { + HMODULE winmm = ::GetModuleHandleA("Winmm.DLL"); + if(0 == winmm) + winmm = ::LoadLibraryA("Winmm.DLL"); + + out_open = reinterpret_cast(::GetProcAddress(winmm, "waveOutOpen")); + out_close = reinterpret_cast(::GetProcAddress(winmm, "waveOutClose")); + out_write = reinterpret_cast(::GetProcAddress(winmm, "waveOutWrite")); + out_prepare = reinterpret_cast(::GetProcAddress(winmm, "waveOutPrepareHeader")); + out_unprepare = reinterpret_cast(::GetProcAddress(winmm, "waveOutUnprepareHeader")); + } + }wave_native_if; +#endif + //class audio_device + audio_device::audio_device() +#if defined(NANA_WINDOWS) + : handle_(nullptr), buf_prep_(nullptr) +#elif defined(NANA_LINUX) + : handle_(nullptr), buf_prep_(nullptr) +#endif + {} + + audio_device::~audio_device() + { + close(); + } + + bool audio_device::empty() const + { + return (nullptr == handle_); + } + + bool audio_device::open(std::size_t channels, std::size_t rate, std::size_t bits_per_sample) + { +#if defined(NANA_WINDOWS) + close(); + + WAVEFORMATEX wfx; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = static_cast(channels); + wfx.nSamplesPerSec = static_cast(rate); + wfx.wBitsPerSample = static_cast(bits_per_sample); + + wfx.nBlockAlign = (wfx.wBitsPerSample >> 3 ) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + wfx.cbSize = 0; + + MMRESULT mmr = wave_native_if.out_open(&handle_, WAVE_MAPPER, &wfx, reinterpret_cast(&audio_device::_m_dev_callback), reinterpret_cast(this), CALLBACK_FUNCTION); + return (mmr == MMSYSERR_NOERROR); +#elif defined(NANA_LINUX) + if(nullptr == handle_) + { + if(::snd_pcm_open(&handle_, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0) < 0) + return false; + } + + if(handle_) + { + channels_ = channels; + rate_ = rate; + bytes_per_sample_ = (bits_per_sample >> 3); + bytes_per_frame_ = bytes_per_sample_ * channels; + + snd_pcm_hw_params_t * params; + if(snd_pcm_hw_params_malloc(¶ms) < 0) + { + close(); + return false; + } + + if(::snd_pcm_hw_params_any(handle_, params) < 0) + { + close(); + ::snd_pcm_hw_params_free(params); + return false; + } + + if(::snd_pcm_hw_params_set_access(handle_, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) + { + close(); + ::snd_pcm_hw_params_free(params); + return false; + } + + snd_pcm_format_t format = SND_PCM_FORMAT_U8; + switch(bits_per_sample) + { + case 8: + format = SND_PCM_FORMAT_U8; break; + case 16: + format = SND_PCM_FORMAT_S16_LE; break; + case 32: + format = SND_PCM_FORMAT_S32_LE; break; + } + + if(::snd_pcm_hw_params_set_format(handle_, params, format) < 0) + { + close(); + ::snd_pcm_hw_params_free(params); + return false; + } + + unsigned tmp = rate; + if(::snd_pcm_hw_params_set_rate_near(handle_, params, &tmp, 0) < 0) + { + close(); + ::snd_pcm_hw_params_free(params); + return false; + } + + if(::snd_pcm_hw_params_set_channels(handle_, params, channels) < 0) + { + close(); + ::snd_pcm_hw_params_free(params); + return false; + } + + if(::snd_pcm_hw_params(handle_, params) < 0) + { + close(); + ::snd_pcm_hw_params_free(params); + return false; + } + + ::snd_pcm_hw_params_free(params); + ::snd_pcm_prepare(handle_); + return true; + } + return false; +#endif + } + + void audio_device::close() + { + if(handle_) + { +#if defined(NANA_WINDOWS) + wave_native_if.out_close(handle_); +#elif defined(NANA_LINUX) + ::snd_pcm_close(handle_); +#endif + handle_ = nullptr; + } + } + + void audio_device::prepare(buffer_preparation & buf_prep) + { + buf_prep_ = & buf_prep; + } + + void audio_device::write(buffer_preparation::meta * m) + { +#if defined(NANA_WINDOWS) + std::lock_guard lock(queue_lock_); + done_queue_.push_back(m); + if(m->dwFlags & WHDR_PREPARED) + wave_native_if.out_unprepare(handle_, m, sizeof(WAVEHDR)); + + wave_native_if.out_prepare(handle_, m, sizeof(WAVEHDR)); + wave_native_if.out_write(handle_, m, sizeof(WAVEHDR)); +#elif defined(NANA_LINUX) + std::size_t frames = m->bufsize / bytes_per_frame_; + std::size_t buffered = 0; //in bytes + while(frames > 0) + { + int err = ::snd_pcm_writei(handle_, m->buf + buffered, frames); + if(err > 0) + { + frames -= err; + buffered += err * bytes_per_frame_; + } + else if(-EPIPE == err) + ::snd_pcm_prepare(handle_); + } + buf_prep_->revert(m); +#endif + } + + void audio_device::wait_for_drain() const + { +#if defined(NANA_WINDOWS) + while(buf_prep_->data_finished() == false) + nana::system::sleep(200); +#elif defined(NANA_LINUX) + while(::snd_pcm_state(handle_) == SND_PCM_STATE_RUNNING) + nana::system::sleep(200); +#endif + } + +#if defined(NANA_WINDOWS) + void __stdcall audio_device::_m_dev_callback(HWAVEOUT handle, UINT msg, audio_device * self, DWORD_PTR, DWORD_PTR) + { + if(WOM_DONE == msg) + { + buffer_preparation::meta * m; + { + std::lock_guard lock(self->queue_lock_); + m = self->done_queue_.front(); + self->done_queue_.erase(self->done_queue_.begin()); + } + wave_native_if.out_unprepare(handle, m, sizeof(WAVEHDR)); + self->buf_prep_->revert(m); + } + } +#endif + //end class audio_device + }//end namespace detail +}//end namespace audio +}//end namespace nana diff --git a/source/audio/detail/audio_stream.cpp b/source/audio/detail/audio_stream.cpp new file mode 100644 index 00000000..96def3d9 --- /dev/null +++ b/source/audio/detail/audio_stream.cpp @@ -0,0 +1,91 @@ +#include +#include + +namespace nana{ namespace audio +{ + namespace detail + { + //class audio_stream + bool audio_stream::open(const nana::string& file) + { + fs_.open(static_cast(nana::charset(file)), std::ios::binary); + if(fs_) + { + wave_spec::master_riff_chunk riff; + fs_.read(reinterpret_cast(&riff), sizeof(riff)); + if(riff.ckID == *reinterpret_cast("RIFF") && riff.waveID == *reinterpret_cast("WAVE")) + { + fs_.read(reinterpret_cast(&ck_format_), sizeof(ck_format_)); + if(ck_format_.ckID == *reinterpret_cast("fmt ") && ck_format_.wFormatTag == 1) //Only support PCM format + { + std::size_t cksize = _m_locate_chunck(*reinterpret_cast("data")); + if(cksize) + { + pcm_data_pos_ = static_cast(fs_.tellg()); + pcm_data_size_ = cksize; + return true; + } + } + } + } + return false; + } + + void audio_stream::close() + { + fs_.close(); + } + + bool audio_stream::empty() const + { + return (!fs_); + } + + const wave_spec::format_chunck & audio_stream::format() const + { + return ck_format_; + } + + std::size_t audio_stream::data_length() const + { + return data_size_; + } + + void audio_stream::locate() + { + fs_.clear(); + fs_.seekg(pcm_data_pos_, std::ios::beg); + data_size_ = pcm_data_size_; + } + + std::size_t audio_stream::read(void * buf, std::size_t len) + { + fs_.read(reinterpret_cast(buf), static_cast(len <= data_size_ ? len : data_size_)); + std::size_t read_bytes = static_cast(fs_.gcount()); + data_size_ -= read_bytes; + return read_bytes; + } + + std::size_t audio_stream::_m_locate_chunck(unsigned ckID) + { + chunck ck; + while(true) + { + fs_.read(reinterpret_cast(&ck), sizeof(ck)); + if(fs_.gcount() != sizeof(ck)) + break; + + if(ck.ckID == ckID) + return ck.cksize; + if(ck.ckID == *reinterpret_cast("data")) + fs_.seekg(ck.cksize + (ck.cksize & 1 ? 1 : 0), std::ios::cur); + else + fs_.seekg(ck.cksize, std::ios::cur); + } + return 0; + } + //end class audio_stream + }//end namespace detail + +}//end namespace audio +}//end namespace nana \ No newline at end of file diff --git a/source/audio/detail/buffer_preparation.cpp b/source/audio/detail/buffer_preparation.cpp new file mode 100644 index 00000000..7c340949 --- /dev/null +++ b/source/audio/detail/buffer_preparation.cpp @@ -0,0 +1,161 @@ +#include +#include + +namespace nana{ namespace audio +{ + namespace detail + { + //class buffer_preparation + buffer_preparation::buffer_preparation(audio_stream& as, std::size_t seconds) + : running_(true), wait_for_buffer_(false), as_(as) + { + //Allocate the space + buffer_.reserve(seconds); + prepared_.reserve(seconds); + + const wave_spec::format_chunck & ck = as.format(); + block_size_ = ck.nAvgBytesPerSec; + for(std::size_t i = 0; i < seconds; ++i) + { + char * rawbuf = new char[sizeof(meta) + ck.nAvgBytesPerSec]; + meta * m = reinterpret_cast(rawbuf); +#if defined(NANA_WINDOWS) + memset(m, 0, sizeof(meta)); + m->dwBufferLength = static_cast(block_size_); + m->lpData = rawbuf + sizeof(meta); +#elif defined(NANA_LINUX) + m->bufsize = ck.nAvgBytesPerSec; + m->buf = rawbuf + sizeof(meta); +#endif + prepared_.push_back(m); + } + + thr_ = std::move(std::thread([this](){this->_m_prepare_routine();})); + } + + buffer_preparation::~buffer_preparation() + { + running_ = false; + + cond_prepared_.notify_one(); + cond_buffer_.notify_one(); + + if(thr_.joinable()) + thr_.join(); + + for(auto metaptr : prepared_) + delete [] reinterpret_cast(metaptr); + } + + buffer_preparation::meta * buffer_preparation::read() + { + std::unique_lock lock(token_buffer_); + + //Wait for the buffer + if(0 == buffer_.size()) + { + //Before waiting, checks the thread whether it is finished + //it indicates the preparation is finished. + if(false == running_) + return nullptr; + + wait_for_buffer_ = true; + cond_buffer_.wait(lock); + + //NO more buffers + if(0 == buffer_.size()) + return nullptr; + } + meta * m = buffer_.front(); + buffer_.erase(buffer_.begin()); + return m; + } + + //Revert the meta that returned by read() + void buffer_preparation::revert(meta * m) + { + std::lock_guard lock(token_prepared_); + bool if_signal = prepared_.empty(); + prepared_.push_back(m); + if(if_signal) + cond_prepared_.notify_one(); + } + + bool buffer_preparation::data_finished() const + { + std::lock_guard lock(token_prepared_); + return ((prepared_.size() == prepared_.capacity()) && (running_ == false)); + } + + void buffer_preparation::_m_prepare_routine() + { + const std::size_t fixed_bufsize = 1024; + char buf[fixed_bufsize]; + const std::size_t block_size = block_size_; + + while(running_) + { + meta * m = 0; + { + std::unique_lock lock(token_prepared_); + + if(prepared_.size() == 0) + { + cond_prepared_.wait(lock); + + if(false == running_) + return; + } + m = prepared_.back(); + prepared_.pop_back(); + } + + std::size_t buffered = 0; + while(buffered != block_size) + { + std::size_t want_bytes = block_size - buffered; + if(want_bytes > fixed_bufsize) want_bytes = fixed_bufsize; + + std::size_t read_bytes = as_.read(buf, want_bytes); + if(read_bytes) + { +#if defined(NANA_WINDOWS) + memcpy(m->lpData + buffered, buf, read_bytes); +#elif defined(NANA_LINUX) + memcpy(m->buf + buffered, buf, read_bytes); +#endif + buffered += read_bytes; + } + else if(0 == as_.data_length()) + { + if(buffered == 0) + { + //PCM data is drained + std::lock_guard lock(token_buffer_); + cond_buffer_.notify_one(); + running_ = false; + return; + } + break; + } + } +#if defined(NANA_WINDOWS) + m->dwBufferLength = static_cast(buffered); +#elif defined(NANA_LINUX) + m->bufsize = buffered; +#endif + std::lock_guard lock(token_buffer_); + buffer_.push_back(m); + if(wait_for_buffer_) + { + cond_buffer_.notify_one(); + wait_for_buffer_ = false; + } + if(0 == as_.data_length()) + running_ = false; + } + } + //end class buffer_preparation + }//end namespace detail +}//end namespace audio +}//end namespace nana diff --git a/source/audio/player.cpp b/source/audio/player.cpp new file mode 100644 index 00000000..5941c073 --- /dev/null +++ b/source/audio/player.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +namespace nana{ namespace audio +{ + //class player + struct player::implementation + { + detail::audio_stream stream; + detail::audio_device dev; + }; + + player::player() + : impl_(new implementation) + {} + + player::player(const nana::string& file) + : impl_(new implementation) + { + open(file); + } + + player::~player() + { + delete impl_; + } + + bool player::open(const nana::string& file) + { + if(impl_->stream.open(file)) + { + const detail::wave_spec::format_chunck & ck = impl_->stream.format(); + return impl_->dev.open(ck.nChannels, ck.nSamplePerSec, ck.wBitsPerSample); + } + return false; + } + + void player::play() + { + if(impl_->dev.empty() || impl_->stream.empty()) return; + + //Locate the PCM + impl_->stream.locate(); + const std::size_t seconds = 5; + + detail::buffer_preparation buffer(impl_->stream, seconds); + impl_->dev.prepare(buffer); + detail::buffer_preparation::meta * meta; + while((meta = buffer.read())) + { + impl_->dev.write(meta); + } + impl_->dev.wait_for_drain(); + } + + void player::close() + { + impl_->dev.close(); + impl_->stream.close(); + } +}//end namespace audio +}//end namespace nana \ No newline at end of file diff --git a/source/basic_types.cpp b/source/basic_types.cpp new file mode 100644 index 00000000..e4cf6acf --- /dev/null +++ b/source/basic_types.cpp @@ -0,0 +1,313 @@ +/* + * Basic Types definition + * Copyright(C) 2003-2013 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/basic_types.cpp + */ + +#include + +namespace nana +{ + //struct point + point::point():x(0), y(0){} + point::point(int x, int y):x(x), y(y){} + point::point(const rectangle& r) + : x(r.x), y(r.y) + {} + + point& point::operator=(const rectangle& r) + { + x = r.x; + y = r.y; + return *this; + } + + bool point::operator==(const point& rhs) const + { + return ((x == rhs.x) && (y == rhs.y)); + } + + bool point::operator!=(const point& rhs) const + { + return ((x != rhs.x) || (y != rhs.y)); + } + + bool point::operator<(const point& rhs) const + { + return ((y < rhs.y) || (y == rhs.y && x < rhs.x)); + } + + bool point::operator<=(const point& rhs) const + { + return ((y < rhs.y) || (y == rhs.y && x <= rhs.x)); + } + + bool point::operator>(const point& rhs) const + { + return ((y > rhs.y) || (y == rhs.y && x > rhs.x)); + } + + bool point::operator>=(const point& rhs) const + { + return ((y > rhs.y) || (y == rhs.y && x >= rhs.x)); + } + + point point::operator-(const point& rhs) const + { + return{x - rhs.x, y - rhs.y}; + } + + point point::operator+(const point& rhs) const + { + return{ x + rhs.x, y + rhs.y }; + } + + point& point::operator-=(const point& rhs) + { + x -= rhs.x; + y -= rhs.y; + return *this; + } + + point& point::operator+=(const point& rhs) + { + x += rhs.x; + y += rhs.y; + return *this; + } + //end struct point + + //struct upoint + upoint::upoint():x(0), y(0){} + upoint::upoint(unsigned x, unsigned y):x(x), y(y){} + + bool upoint::operator==(const upoint& rhs) const + { + return ((x == rhs.x) && (y == rhs.y)); + } + + bool upoint::operator!=(const upoint& rhs) const + { + return ((x != rhs.x) || (y != rhs.y)); + } + + bool upoint::operator<(const upoint& rhs) const + { + return ((y < rhs.y) || (y == rhs.y && x < rhs.x)); + } + + bool upoint::operator<=(const upoint& rhs) const + { + return ((y < rhs.y) || (y == rhs.y && x <= rhs.x)); + } + + bool upoint::operator>(const upoint& rhs) const + { + return ((y > rhs.y) || (y == rhs.y && x > rhs.x)); + } + + bool upoint::operator>=(const upoint& rhs) const + { + return ((y > rhs.y) || (y == rhs.y && x >= rhs.x)); + } + //end struct upoint + + //struct size + size::size():width(0), height(0){} + size::size(unsigned width, unsigned height):width(width), height(height){} + size::size(const rectangle& r) + : width(r.width), height(r.height) + {} + + size& size::operator=(const rectangle& r) + { + width = r.width; + height = r.height; + return *this; + } + + bool size::empty() const + { + return (0 == width || 0 == height); + } + + bool size::is_hit(const point& pos) const + { + return (0 <= pos.x && pos.x < static_cast(width) && 0 <= pos.y && pos.y < static_cast(height)); + } + + bool size::operator==(const size& rhs) const + { + return (width == rhs.width) && (height == rhs.height); + } + + bool size::operator!=(const size& rhs) const + { + return (width != rhs.width) || (height != rhs.height); + } + + size size::operator+(const size& sz) const + { + return{width + sz.width, height + sz.height}; + } + //end struct size + + //struct rectangle + rectangle::rectangle() + :x(0), y(0), width(0), height(0) + {} + + rectangle::rectangle(int x, int y, unsigned width, unsigned height) + :x(x), y(y), width(width), height(height) + {} + + rectangle::rectangle(const size & sz) + :x(0), y(0), width(sz.width), height(sz.height) + {} + + rectangle::rectangle(const point & pos, const size& sz) + : x(pos.x), y(pos.y), width(sz.width), height(sz.height) + {} + + bool rectangle::operator==(const rectangle& rhs) const + { + return (width == rhs.width) && (height == rhs.height) && (x == rhs.x) && (y == rhs.y); + } + + bool rectangle::operator!=(const rectangle& rhs) const + { + return (width != rhs.width) || (height != rhs.height) || (x != rhs.x) || (y != rhs.y); + } + + rectangle & rectangle::operator=(const point& pos) + { + x = pos.x; + y = pos.y; + return *this; + } + + rectangle & rectangle::operator=(const size & sz) + { + width = sz.width; + height = sz.height; + return *this; + } + + rectangle& rectangle::set_pos(const point& pos) + { + x = pos.x; + y = pos.y; + return *this; + } + + rectangle& rectangle::set_size(const size& sz) + { + width = sz.width; + height = sz.height; + return *this; + } + + rectangle& rectangle::pare_off(int pixels) + { + x += pixels; + y += pixels; + width -= (pixels << 1); + height -= (pixels << 1); + return *this; + } + + int rectangle::right() const + { + return static_cast(x + width); + } + + int rectangle::bottom() const + { + return static_cast(y + height); + } + + bool rectangle::is_hit(int pos_x, int pos_y) const + { + return (x <= pos_x && pos_x < x + static_cast(width)) && + (y <= pos_y && pos_y < y + static_cast(height)); + } + + bool rectangle::is_hit(const point& pos) const + { + return (x <= pos.x && pos.x < x + static_cast(width)) && + (y <= pos.y && pos.y < y + static_cast(height)); + } + + bool rectangle::empty() const + { + return (0 == width) || (0 == height); + } + //end struct rectangle + + //class area_rotator + area_rotator::area_rotator(bool rotated, const ::nana::rectangle& area) + : rotated_(rotated), + area_(area) + {} + + int area_rotator::x() const + { + return (rotated_ ? area_.y : area_.x); + } + + int & area_rotator::x_ref() + { + return (rotated_ ? area_.y : area_.x); + } + + int area_rotator::y() const + { + return (rotated_ ? area_.x : area_.y); + } + + int & area_rotator::y_ref() + { + return (rotated_ ? area_.x : area_.y); + } + + unsigned area_rotator::w() const + { + return (rotated_ ? area_.height : area_.width); + } + + unsigned & area_rotator::w_ref() + { + return (rotated_ ? area_.height : area_.width); + } + + unsigned area_rotator::h() const + { + return (rotated_ ? area_.width : area_.height); + } + + unsigned & area_rotator::h_ref() + { + return (rotated_ ? area_.width : area_.height); + } + + int area_rotator::right() const + { + return (rotated_ ? area_.y + static_cast(area_.height) : area_.x + static_cast(area_.width)); + } + + int area_rotator::bottom() const + { + return (rotated_ ? area_.x + static_cast(area_.width) : area_.y + static_cast(area_.height)); + } + + const ::nana::rectangle& area_rotator::result() const + { + return area_; + } + //end class area_rotator +} diff --git a/source/charset.cpp b/source/charset.cpp new file mode 100644 index 00000000..6a28b774 --- /dev/null +++ b/source/charset.cpp @@ -0,0 +1,1071 @@ +/* + * A Character Encoding Set Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/charset.cpp + * @brief: A conversion between unicode characters and multi bytes characters + * @contributions: + * UTF16 4-byte decoding issue by Renke Yan. + */ + +#include +#include +#include +#include +#include + +//GCC 4.7.0 does not implement the and codecvt_utfx classes +#ifndef STD_CODECVT_NOT_SUPPORTED + #include +#endif + +#if defined(NANA_MINGW) + #include +#endif + +namespace nana +{ + namespace detail + { + class locale_initializer + { + public: + static void init() + { + static bool initialized = false; + if(false == initialized) + { + initialized = true; + //Only set the C library locale + std::setlocale(LC_CTYPE, ""); + } + } + }; + + bool wc2mb(std::string& mbstr, const wchar_t * s) + { + if(nullptr == s || *s == 0) + { + mbstr.clear(); + return true; + } +#if defined(NANA_MINGW) + int bytes = ::WideCharToMultiByte(CP_ACP, 0, s, -1, 0, 0, 0, 0); + if(bytes > 1) + { + mbstr.resize(bytes - 1); + ::WideCharToMultiByte(CP_ACP, 0, s, -1, &(mbstr[0]), bytes - 1, 0, 0); + } + return true; +#else + locale_initializer::init(); + std::mbstate_t mbstate = std::mbstate_t(); + std::size_t len = std::wcsrtombs(nullptr, &s, 0, &mbstate); + if(len == static_cast(-1)) + return false; + + if(len) + { + mbstr.resize(len); + std::wcsrtombs(&(mbstr[0]), &s, len, &mbstate); + } + else + mbstr.clear(); +#endif + return true; + } + + bool mb2wc(std::wstring& wcstr, const char* s) + { + if(nullptr == s || *s == 0) + { + wcstr.clear(); + return true; + } +#if defined(NANA_MINGW) + int chars = ::MultiByteToWideChar(CP_ACP, 0, s, -1, 0, 0); + if(chars > 1) + { + wcstr.resize(chars - 1); + ::MultiByteToWideChar(CP_ACP, 0, s, -1, &wcstr[0], chars - 1); + } +#else + locale_initializer::init(); + std::mbstate_t mbstate = std::mbstate_t(); + std::size_t len = std::mbsrtowcs(nullptr, &s, 0, &mbstate); + if(len == static_cast(-1)) + return false; + + if(len) + { + wcstr.resize(len); + std::mbsrtowcs(&wcstr[0], &s, len, &mbstate); + } + else + wcstr.clear(); +#endif + return true; + } + + bool mb2wc(std::string& wcstr, const char* s) + { + if(nullptr == s || *s == 0) + { + wcstr.clear(); + return true; + } +#if defined(NANA_MINGW) + int chars = ::MultiByteToWideChar(CP_ACP, 0, s, -1, 0, 0); + if(chars > 1) + { + wcstr.resize((chars - 1) * sizeof(wchar_t)); + ::MultiByteToWideChar(CP_ACP, 0, s, -1, reinterpret_cast(&wcstr[0]), chars - 1); + } +#else + locale_initializer::init(); + std::mbstate_t mbstate = std::mbstate_t(); + std::size_t len = std::mbsrtowcs(nullptr, &s, 0, &mbstate); + if(len == static_cast(-1)) + return false; + + if(len) + { + wcstr.resize(sizeof(wchar_t) * len); + std::mbsrtowcs(reinterpret_cast(&wcstr[0]), &s, len, &mbstate); + } + else + wcstr.clear(); +#endif + return true; + } + + class charset_encoding_interface + { + public: + virtual ~charset_encoding_interface(){} + + virtual charset_encoding_interface * clone() const = 0; + + virtual std::string str() const = 0; + virtual std::string&& str_move() = 0; + virtual std::string str(unicode) const = 0; + + virtual std::wstring wstr() const = 0; + virtual std::wstring&& wstr_move() = 0; + }; + +#ifndef STD_CODECVT_NOT_SUPPORTED + class charset_string + : public charset_encoding_interface + { + public: + charset_string(const std::string& s) + : data_(s), is_unicode_(false) + {} + + charset_string(std::string&& s) + : data_(std::move(s)), is_unicode_(false) + {} + + charset_string(const std::string& s, unicode encoding) + : data_(s), is_unicode_(true), utf_x_(encoding) + {} + + charset_string(std::string&& s, unicode encoding) + : data_(std::move(s)), is_unicode_(true), utf_x_(encoding) + {} + private: + virtual charset_encoding_interface * clone() const + { + return new charset_string(*this); + } + + virtual std::string str() const + { + if(is_unicode_) + { + std::wstring wcstr; + switch(utf_x_) + { + case unicode::utf8: + wcstr = std::wstring_convert>().from_bytes(data_); + break; + case unicode::utf16: + wcstr = std::wstring_convert>().from_bytes(data_); + break; + case unicode::utf32: + wcstr.append(reinterpret_cast(data_.c_str()), data_.size() / sizeof(wchar_t)); + break; + } + + std::string mbstr; + wc2mb(mbstr, wcstr.c_str()); + return mbstr; + } + return data_; + } + + virtual std::string&& str_move() + { + if(is_unicode_) + data_ = std::move(str()); + return std::move(data_); + } + + virtual std::string str(unicode encoding) const + { + if(is_unicode_ && (utf_x_ != encoding)) + { + switch(utf_x_) + { + case unicode::utf8: + switch(encoding) + { + case unicode::utf16: + return std::wstring_convert, char16_t>().to_bytes( + std::wstring_convert, char16_t>().from_bytes(data_) + ); + case unicode::utf32: + { + std::u32string u32str = std::wstring_convert, char32_t>().from_bytes(data_); + return std::string(reinterpret_cast(u32str.c_str()), u32str.size() * sizeof(char32_t)); + } + } + break; + case unicode::utf16: + switch(encoding) + { + case unicode::utf8: + return std::wstring_convert, char16_t>().to_bytes( + std::wstring_convert, char16_t>().from_bytes(data_) + ); + case unicode::utf32: + { + std::u32string u32str = std::wstring_convert, char32_t>().from_bytes(data_); + return std::string(reinterpret_cast(u32str.c_str()), u32str.size() * sizeof(char32_t)); + } + } + break; + case unicode::utf32: + switch(encoding) + { + case unicode::utf8: + return std::wstring_convert, char32_t>().to_bytes( + std::u32string(reinterpret_cast(data_.c_str()), data_.size() / sizeof(char32_t)) + ); + case unicode::utf16: + return std::wstring_convert, char32_t>().to_bytes( + std::u32string(reinterpret_cast(data_.c_str()), data_.size() / sizeof(char32_t)) + ); + } + break; + } + return{}; + } + + std::wstring wcstr; + if(mb2wc(wcstr, data_.c_str())) + { + switch(encoding) + { + case unicode::utf8: + return std::wstring_convert>().to_bytes(wcstr); + case unicode::utf16: + return std::wstring_convert>().to_bytes(wcstr); + case unicode::utf32: + #if defined(NANA_WINDOWS) + { + const char * bytes = reinterpret_cast(wcstr.c_str()); + std::u32string utf32str = std::wstring_convert, char32_t>().from_bytes(bytes, bytes + sizeof(wchar_t) * wcstr.size()); + return std::string(reinterpret_cast(utf32str.c_str()), sizeof(char32_t) * utf32str.size()); + } + #elif defined(NANA_LINUX) + return std::string(reinterpret_cast(wcstr.c_str()), sizeof(wchar_t) * wcstr.size()); + #else + throw std::runtime_error("Bad charset"); + #endif + } + } + return{}; + } + + virtual std::wstring wstr() const + { + if(is_unicode_) + { + switch(utf_x_) + { + case unicode::utf8: + return std::wstring_convert>().from_bytes(data_); + case unicode::utf16: + return std::wstring_convert>().from_bytes(data_); + case unicode::utf32: + return std::wstring(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)); + } + return{}; + } + + std::wstring wcstr; + mb2wc(wcstr, data_.c_str()); + return wcstr; + } + + virtual std::wstring && wstr_move() + { + wdata_for_move_ = std::move(wstr()); + return std::move(wdata_for_move_); + } + private: + std::string data_; + std::wstring wdata_for_move_; + bool is_unicode_; + unicode utf_x_; + }; + + class charset_wstring + : public charset_encoding_interface + { + public: + charset_wstring(const std::wstring& s) + : data_(s) + {} + + charset_wstring(std::wstring&& s) + : data_(std::move(s)) + {} + + virtual charset_encoding_interface * clone() const + { + return new charset_wstring(*this); + } + + virtual std::string str() const + { + if(data_.size()) + { + std::string mbstr; + wc2mb(mbstr, data_.c_str()); + return mbstr; + } + return{}; + } + + virtual std::string&& str_move() + { + data_for_move_ = str(); + return std::move(data_for_move_); + } + + virtual std::string str(unicode encoding) const + { + switch(encoding) + { + case unicode::utf8: + return std::wstring_convert>().to_bytes(data_); + case unicode::utf16: + return std::wstring_convert>().to_bytes(data_); + case unicode::utf32: + #if defined (NANA_WINDOWS) + { + const char* bytes = reinterpret_cast(data_.c_str()); + std::u32string utf32str = std::wstring_convert, char32_t>().from_bytes(bytes, bytes + sizeof(wchar_t) * data_.size()); + return std::string(reinterpret_cast(utf32str.c_str()), sizeof(char32_t) * utf32str.size()); + } + #elif defined(NANA_LINUX) + return std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)); + #else + throw std::runtime_error("Bad charset"); + #endif + } + return std::string(); + } + + virtual std::wstring wstr() const + { + return data_; + } + + virtual std::wstring&& wstr_move() + { + return std::move(data_); + } + private: + std::wstring data_; + std::string data_for_move_; + }; +#else + unsigned long utf8char(const unsigned char*& p, const unsigned char* end) + { + if(p != end) + { + if(*p < 0x80) + { + return *(p++); + } + unsigned ch = *p; + unsigned long code; + if(ch < 0xC0) + { + p = end; + return 0; + } + else if(ch < 0xE0 && (p + 1 <= end)) + { + code = ((ch & 0x1F) << 6) | (p[1] & 0x3F); + p += 2; + } + else if(ch < 0xF0 && (p + 2 <= end)) + { + code = ((((ch & 0xF) << 6) | (p[1] & 0x3F)) << 6) | (p[2] & 0x3F); + p += 3; + } + else if(ch < 0x1F && (p + 3 <= end)) + { + code = ((((((ch & 0x7) << 6) | (p[1] & 0x3F)) << 6) | (p[2] & 0x3F)) << 6) | (p[3] & 0x3F); + p += 4; + } + else + { + p = end; + return 0; + } + return code; + } + return 0; + } + + unsigned long utf16char(const unsigned char* & bytes, const unsigned char* end, bool le_or_be) + { + unsigned long code; + if(le_or_be) + { + if((end - bytes >= 4) && ((bytes[1] & 0xFC) == 0xD8)) + { + //32bit encoding + unsigned long ch0 = bytes[0] | (bytes[1] << 8); + unsigned long ch1 = bytes[2] | (bytes[3] << 8); + + code = ((ch0 & 0x3FF) << 10) | (ch1 & 0x3FF); + bytes += 4; + } + else if(end - bytes >= 2) + { + code = bytes[0] | (bytes[1] << 8); + bytes += 2; + } + else + { + bytes = end; + return 0; + } + } + else + { + if((end - bytes >= 4) && ((bytes[0] & 0xFC) == 0xD8)) + { + //32bit encoding + unsigned long ch0 = (bytes[0] << 8) | bytes[1]; + unsigned long ch1 = (bytes[2] << 8) | bytes[3]; + code = (((ch0 & 0x3FF) << 10) | (ch1 & 0x3FF)) + 0x10000; + bytes += 4; + } + else if(end - bytes >= 2) + { + code = (bytes[0] << 8) | bytes[1]; + bytes += 2; + } + else + { + bytes = end; + return 0; + } + } + return code; + } + + unsigned long utf32char(const unsigned char* & bytes, const unsigned char* end, bool le_or_be) + { + if(end - bytes >= 4) + { + unsigned long code; + if(le_or_be) + code = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); + else + code = bytes[3] | (bytes[2] << 8) | (bytes[1] << 16) | (bytes[0] << 24); + bytes += 4; + return code; + } + bytes = end; + return 0; + } + + void put_utf8char(std::string& s, unsigned long code) + { + if(code < 0x80) + { + s += static_cast(code); + } + else if(code < 0x800) + { + s += static_cast(0xC0 | (code >> 6)); + s += static_cast(0x80 | (code & 0x3F)); + } + else if(code < 0x10000) + { + s += static_cast(0xE0 | (code >> 12)); + s += static_cast(0x80 | ((code >> 6) & 0x3F)); + s += static_cast(0x80 | (code & 0x3F)); + } + else + { + s += static_cast(0xF0 | (code >> 18)); + s += static_cast(0x80 | ((code >> 12) & 0x3F)); + s += static_cast(0x80 | ((code >> 6) & 0x3F)); + s += static_cast(0x80 | (code & 0x3F)); + } + } + + //le_or_be, true = le, false = be + void put_utf16char(std::string& s, unsigned long code, bool le_or_be) + { + if(code <= 0xFFFF) + { + if(le_or_be) + { + s += static_cast(code & 0xFF); + s += static_cast((code & 0xFF00) >> 8); + } + else + { + s += static_cast((code & 0xFF00) >> 8); + s += static_cast(code & 0xFF); + } + } + else + { + unsigned long ch0 = (0xD800 | ((code - 0x10000) >> 10)); + unsigned long ch1 = (0xDC00 | ((code - 0x10000) & 0x3FF)); + + if(le_or_be) + { + s += static_cast(ch0 & 0xFF); + s += static_cast((ch0 & 0xFF00) >> 8); + + s += static_cast(ch1 & 0xFF); + s += static_cast((ch1 & 0xFF00) >> 8); + } + else + { + s += static_cast((ch0 & 0xFF00) >> 8); + s += static_cast(ch0 & 0xFF); + + s += static_cast((ch1 & 0xFF00) >> 8); + s += static_cast(ch1 & 0xFF); + } + } + } + + void put_utf32char(std::string& s, unsigned long code, bool le_or_be) + { + if(le_or_be) + { + s += static_cast(code & 0xFF); + s += static_cast((code & 0xFF00) >> 8); + s += static_cast((code & 0xFF0000) >> 16); + s += static_cast((code & 0xFF000000) >> 24); + } + else + { + s += static_cast((code & 0xFF000000) >> 24); + s += static_cast((code & 0xFF0000) >> 16); + s += static_cast((code & 0xFF00) >> 8); + s += static_cast(code & 0xFF); + } + } + + std::string utf8_to_utf16(const std::string& s, bool le_or_be) + { + const unsigned char * bytes = reinterpret_cast(s.c_str()); + const unsigned char * end = bytes + s.size(); + + std::string utf16str; + + //If there is a BOM, ignore it. + if(s.size() >= 3) + { + if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) + { + bytes += 3; + put_utf16char(utf16str, 0xFEFF, le_or_be); + } + } + + while(bytes != end) + { + put_utf16char(utf16str, utf8char(bytes, end), le_or_be); + } + return utf16str; + } + + std::string utf8_to_utf32(const std::string& s, bool le_or_be) + { + const unsigned char * bytes = reinterpret_cast(s.c_str()); + const unsigned char * end = bytes + s.size(); + + std::string utf32str; + //If there is a BOM, ignore it. + if(s.size() >= 3) + { + if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) + { + bytes += 3; + put_utf32char(utf32str, 0xFEFF, le_or_be); + } + } + + while(bytes != end) + { + put_utf32char(utf32str, utf8char(bytes, end), le_or_be); + } + return utf32str; + } + + std::string utf16_to_utf8(const std::string& s) + { + const unsigned char * bytes = reinterpret_cast(s.c_str()); + const unsigned char * end = bytes + s.size(); + bool le_or_be = true; + std::string utf8str; + //If there is a BOM, ignore it + if(s.size() >= 2) + { + if(bytes[0] == 0xFF && bytes[1] == 0xFE) + { + bytes += 2; + le_or_be = true; + + utf8str += (char)0xEF; + utf8str += (char)0xBB; + utf8str += (char)0xBF; + } + else if(bytes[0] == 0xFE && bytes[1] == 0xFF) + { + bytes += 2; + le_or_be = false; + utf8str += (char)(0xEF); + utf8str += (char)(0xBB); + utf8str += (char)(0xBF); + } + } + + while(bytes != end) + { + put_utf8char(utf8str, utf16char(bytes, end, le_or_be)); + } + return utf8str; + } + + std::string utf16_to_utf32(const std::string& s) + { + const unsigned char * bytes = reinterpret_cast(s.c_str()); + const unsigned char * end = bytes + s.size(); + bool le_or_be = true; + std::string utf32str; + //If there is a BOM, ignore it + if(s.size() >= 2) + { + if(bytes[0] == 0xFF && bytes[1] == 0xFE) + { + bytes += 2; + le_or_be = true; + put_utf32char(utf32str, 0xFEFF, true); + } + else if(bytes[0] == 0xFE && bytes[1] == 0xFF) + { + bytes += 2; + le_or_be = false; + put_utf32char(utf32str, 0xFEFF, false); + } + } + + while(bytes != end) + { + put_utf32char(utf32str, utf16char(bytes, end, le_or_be), le_or_be); + } + return utf32str; + } + + std::string utf32_to_utf8(const std::string& s) + { + const unsigned char * bytes = reinterpret_cast(s.c_str()); + const unsigned char * end = bytes + (s.size() & (~4 + 1)); + + std::string utf8str; + bool le_or_be = true; + //If there is a BOM, ignore it + if(s.size() >= 4) + { + if(bytes[0] == 0 && bytes[1] == 0 && bytes[2] == 0xFE && bytes[3] == 0xFF) + { + le_or_be = false; + bytes += 4; + utf8str += (char)0xEF; + utf8str += (char)0xBB; + utf8str += (char)0xBF; + } + else if(bytes[0] == 0xFF && bytes[1] == 0xFE && bytes[2] == 0 && bytes[3] == 0) + { + le_or_be = true; + bytes += 4; + utf8str += (char)0xEF; + utf8str += (char)0xBB; + utf8str += (char)0xBF; + } + } + + while(bytes < end) + { + put_utf8char(utf8str, utf32char(bytes, end, le_or_be)); + } + return utf8str; + } + + std::string utf32_to_utf16(const std::string& s) + { + const unsigned char * bytes = reinterpret_cast(s.c_str()); + const unsigned char * end = bytes + (s.size() & (~4 + 1)); + + std::string utf16str; + bool le_or_be = true; + //If there is a BOM, ignore it + if(s.size() >= 4) + { + if(bytes[0] == 0 && bytes[1] == 0 && bytes[2] == 0xFE && bytes[3] == 0xFF) + { + le_or_be = false; + bytes += 4; + put_utf16char(utf16str, 0xFEFF, false); + } + else if(bytes[0] == 0xFF && bytes[1] == 0xFE && bytes[2] == 0 && bytes[3] == 0) + { + le_or_be = true; + bytes += 4; + put_utf16char(utf16str, 0xFEFF, true); + } + } + + while(bytes < end) + { + put_utf16char(utf16str, utf32char(bytes, end, le_or_be), le_or_be); + } + return utf16str; + } + + class charset_string + : public charset_encoding_interface + { + public: + charset_string(const std::string& s) + : data_(s), is_unicode_(false) + {} + + charset_string(std::string&& s) + : data_(std::move(s)), is_unicode_(false) + {} + + charset_string(const std::string& s, unicode encoding) + : data_(s), is_unicode_(true), utf_x_(encoding) + {} + + charset_string(std::string&& s, unicode encoding) + : data_(std::move(s)), is_unicode_(true), utf_x_(encoding) + {} + private: + virtual charset_encoding_interface * clone() const + { + return new charset_string(*this); + } + + virtual std::string str() const + { + if(is_unicode_) + { + std::string strbuf; + switch(utf_x_) + { + case unicode::utf8: + strbuf = detail::utf8_to_utf32(data_, true); + detail::put_utf32char(strbuf, 0, true); + break; + case unicode::utf16: + strbuf = detail::utf16_to_utf32(data_); + detail::put_utf32char(strbuf, 0, true); + break; + case unicode::utf32: + strbuf = data_; + detail::put_utf32char(strbuf, 0, true); + break; + } + + std::string mbstr; + wc2mb(mbstr, reinterpret_cast(strbuf.c_str())); + return mbstr; + } + return data_; + } + + virtual std::string && str_move() + { + if(is_unicode_) + data_ = std::move(str()); + return std::move(data_); + } + + virtual std::string str(unicode encoding) const + { + if(is_unicode_ && (utf_x_ != encoding)) + { + switch(utf_x_) + { + case unicode::utf8: + switch(encoding) + { + case unicode::utf16: + return detail::utf8_to_utf16(data_, true); + case unicode::utf32: + return detail::utf8_to_utf32(data_, true); + default: + break; + } + break; + case unicode::utf16: + switch(encoding) + { + case unicode::utf8: + return detail::utf16_to_utf8(data_); + case unicode::utf32: + return detail::utf16_to_utf32(data_); + default: + break; + } + break; + case unicode::utf32: + switch(encoding) + { + case unicode::utf8: + return detail::utf32_to_utf8(data_); + case unicode::utf16: + return detail::utf32_to_utf16(data_); + default: + break; + } + break; + } + return {}; + } + std::string wcstr; + if(mb2wc(wcstr, data_.c_str())) + { + switch(encoding) + { + case unicode::utf8: + return utf32_to_utf8(wcstr); + case unicode::utf16: + return utf32_to_utf16(wcstr); + case unicode::utf32: + return wcstr; + } + } + return {}; + } + + virtual std::wstring wstr() const + { + if(is_unicode_) + { + std::string bytes; + switch(utf_x_) + { + case unicode::utf8: + bytes = detail::utf8_to_utf32(data_, true); + break; + case unicode::utf16: + bytes = detail::utf16_to_utf32(data_); + break; + case unicode::utf32: + bytes = data_; + break; + } + return std::wstring(reinterpret_cast(bytes.c_str()), bytes.size() / sizeof(wchar_t)); + } + + std::wstring wcstr; + mb2wc(wcstr, data_.c_str()); + return wcstr; + } + + virtual std::wstring&& wstr_move() + { + wdata_for_move_ = std::move(wstr()); + return std::move(wdata_for_move_); + } + private: + std::string data_; + std::wstring wdata_for_move_; + bool is_unicode_; + unicode utf_x_; + }; + + + class charset_wstring + : public charset_encoding_interface + { + public: + charset_wstring(const std::wstring& s) + : data_(s) + {} + + virtual charset_encoding_interface * clone() const + { + return new charset_wstring(*this); + } + + virtual std::string str() const + { + if(data_.size()) + { + std::string mbstr; + wc2mb(mbstr, data_.c_str()); + return mbstr; + } + return {}; + } + + virtual std::string && str_move() + { + data_for_move_ = std::move(str()); + return std::move(data_for_move_); + } + + virtual std::string str(unicode encoding) const + { + switch(encoding) + { + case unicode::utf8: + return detail::utf32_to_utf8(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t))); + case unicode::utf16: + return detail::utf32_to_utf16(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t))); + case unicode::utf32: + return std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)); + } + return {}; + } + + virtual std::wstring wstr() const + { + return data_; + } + + virtual std::wstring && wstr_move() + { + return std::move(data_); + } + private: + std::wstring data_; + std::string data_for_move_; + }; +#endif + } + //class charset + charset::charset(const charset& rhs) + : impl_(rhs.impl_ ? rhs.impl_->clone() : 0) + {} + + charset & charset::operator=(const charset& rhs) + { + if(this != &rhs) + { + delete impl_; + impl_ = (rhs.impl_ ? rhs.impl_->clone() : 0); + } + return *this; + } + + charset::charset(charset&& r) + : impl_(r.impl_) + { + r.impl_ = 0; + } + + charset & charset::operator=(charset&& r) + { + if(this != &r) + { + delete impl_; + impl_ = r.impl_; + r.impl_ = nullptr; + } + return *this; + } + + charset::charset(const std::string& s) + : impl_(new detail::charset_string(s)) + {} + + charset::charset(std::string&& s) + : impl_(new detail::charset_string(std::move(s))) + {} + + charset::charset(const std::string& s, unicode encoding) + : impl_(new detail::charset_string(s, encoding)) + {} + + charset::charset(std::string&& s, unicode encoding) + : impl_(new detail::charset_string(std::move(s), encoding)) + {} + + charset::charset(const std::wstring& s) + : impl_(new detail::charset_wstring(s)) + {} + + charset::charset(std::wstring&& s) + : impl_(new detail::charset_wstring(std::move(s))) + {} + + charset::~charset() + { + delete impl_; + } + + charset::operator std::string() const + { + return impl_->str(); + } + + charset::operator std::string&&() + { + return impl_->str_move(); + } + + charset::operator std::wstring() const + { + return impl_->wstr(); + } + + charset::operator std::wstring&&() + { + return impl_->wstr_move(); + } + + std::string charset::to_bytes(unicode encoding) const + { + return impl_->str(encoding); + } + //end class charset + +}//end namespace nana diff --git a/source/datetime.cpp b/source/datetime.cpp new file mode 100644 index 00000000..04baa49d --- /dev/null +++ b/source/datetime.cpp @@ -0,0 +1,274 @@ +/* + * A Date Time Implementation + * Copyright(C) 2003-2013 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/datetime.cpp + */ + +#include +#include +#if defined(NANA_WINDOWS) + #include +#endif + +namespace nana +{ + //class date + date::date() + { + time_t t = std::time(nullptr); + struct tm * tm_addr = std::localtime(&t); + value_.year = tm_addr->tm_year + 1900; + value_.month = tm_addr->tm_mon + 1; + value_.day = tm_addr->tm_mday; + } + + date::date(const std::tm& t) + { + value_.year = t.tm_year + 1900; + value_.month = t.tm_mon + 1; + value_.day = t.tm_mday; + } + + date::date(int year, int month, int day) + { + if(1601 <= year && year < 30827 && 0 < month && month < 13 && day > 0) + { + if(day <= static_cast(date::month_days(year, month))) + { + value_.year = year; + value_.month = month; + value_.day = day; + return; + } + } + + time_t t = std::time(0); + struct tm * tm_addr = std::localtime(&t); + value_.year = tm_addr->tm_year + 1900; + value_.month = tm_addr->tm_mon + 1; + value_.day = tm_addr->tm_mday; + } + + date date::operator - (int off) const + { + if(off < 0) + return _m_add(static_cast(-off)); + return _m_sub(static_cast(off)); + } + + date date::operator + (int off) const + { + if(off < 0) + return _m_sub(static_cast(-off)); + return _m_add(static_cast(off)); + } + + bool date::operator==(const date& r) const + { + return (r.value_.year == value_.year && r.value_.month == value_.month && r.value_.day == value_.day); + } + + bool date::operator!=(const date& r) const + { + return ! (this->operator==(r)); + } + + bool date::operator <(const date & r) const + { + if(value_.year < r.value_.year) + { + return true; + } + else if(value_.year == r.value_.year) + { + if(value_.month < r.value_.month) + return true; + else if(value_.month == r.value_.month) + return (value_.day < r.value_.day); + } + return false; + } + + bool date::operator>(const date & r) const + { + if(value_.year > r.value_.year) + { + return true; + } + else if(value_.year == r.value_.year) + { + if(value_.month > r.value_.month) + return true; + else if(value_.month == r.value_.month) + return (value_.day > r.value_.day); + } + return false; + } + + bool date::operator<=(const date& r) const + { + return !(this->operator>(r)); + } + + bool date::operator>=(const date& r) const + { + return !(this->operator<(r)); + } + + int date::day_of_week() const + { + return day_of_week(static_cast(value_.year), static_cast(value_.month), static_cast(value_.day)); + } + + int date::day_of_week(int year, int month, int day) + { + //w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1; + //the Jan and Feb of Every year are treated as the 13th/14th month of last year. + + if(month < 3) + { + month += 12; + --year; + } + + int century = year / 100; + year = year % 100; + + int w = year + (year / 4) + (century / 4) - (2 * century) + (26 * ( month + 1) / 10) + day - 1; + + if(w >= 0) + return (w % 7); + return ((1 - (w / 7)) * 7 + w); + } + + const date::value & date::read() const + { + return this->value_; + } + + date date::_m_add(unsigned x) const + { + date d(*this); + while(x) + { + unsigned off = month_days(d.value_.year, d.value_.month) - d.value_.day; + if(off < x) + { + d.value_.day = 1; + if(d.value_.month == 12) + { + d.value_.month = 1; + ++ d.value_.year; + } + else + ++ d.value_.month; + + x -= (off + 1); + } + else if(off >= x) + { + d.value_.day += x; + break; + } + } + return d; + } + + date date::_m_sub(unsigned x) const + { + date d(*this); + while(x) + { + if(d.value_.day <= x) + { + if(d.value_.month == 1) + { + d.value_.month = 12; + -- d.value_.year; + } + else + -- d.value_.month; + + d.value_.day = month_days(d.value_.year, d.value_.month); + + x -= d.value_.day; + } + else + { + d.value_.day -= x; + break; + } + } + return d; + } + + unsigned date::day_in_year(unsigned y, unsigned m, unsigned d) + { + unsigned days = 0; + for(unsigned i = 1; i < m; ++i) + days += month_days(y, i); + return days + d; + } + + unsigned date::month_days(unsigned year, unsigned month) + { + unsigned num[] = {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if(month != 2) + return num[month - 1]; + + if(((year % 4 == 0) && (year % 100)) || (year % 400 == 0)) + return 29; + return 28; + } + + unsigned date::year_days(unsigned year) + { + if(((year % 4 == 0) && (year % 100)) || (year % 400 == 0)) + return 366; + return 365; + } + //end class date + + //class time + time::time() + { + time_t t = ::time(0); + struct tm * tm_addr = ::localtime(&t); + value_.hour = tm_addr->tm_hour; + value_.minute = tm_addr->tm_min; + value_.second = tm_addr->tm_sec; + } + + time::time(const std::tm& t) + { + value_.hour = t.tm_hour; + value_.minute = t.tm_min; + value_.second = t.tm_sec; + } + + time::time(unsigned hour, unsigned minute, unsigned second) + { + if(hour < 24 && minute < 60 && second < 62) + { + value_.hour = hour; + value_.minute = minute; + value_.second = second; + } + time_t t = ::time(0); + struct tm * tm_addr = ::localtime(&t); + value_.hour = tm_addr->tm_hour; + value_.minute = tm_addr->tm_min; + value_.second = tm_addr->tm_sec; + } + + const time::value& time::read() const + { + return value_; + } + //end class time +}//end namespace nana diff --git a/source/deploy.cpp b/source/deploy.cpp new file mode 100644 index 00000000..d326ba7c --- /dev/null +++ b/source/deploy.cpp @@ -0,0 +1,73 @@ +/* + * The Deploy Implementation + * Copyright(C) 2003-2013 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/depoly.cpp + * + * What follow are dependented on what defined in nana/config.hpp + */ + +#include + +#if defined(NANA_WINDOWS) + #include +#elif defined(NANA_LINUX) + #include + #include PLATFORM_SPEC_HPP +#endif + +namespace nana +{ + std::size_t strlen(const char_t* str) + { +#if defined(NANA_UNICODE) + return ::wcslen(str); +#else + return ::strlen(str); +#endif + } + + double strtod(const char_t* str, char_t** endptr) + { +#if defined(NANA_UNICODE) + return ::wcstod(str, endptr); +#else + return ::strtod(str, endptr); +#endif + } + + char_t* strcpy(char_t* dest, const char_t* source) + { +#if defined(NANA_UNICODE) + return ::wcscpy(dest, source); +#else + return ::strcpy(dest, source); +#endif + } + + bool is_incomplete(const nana::string& str, unsigned pos) + { +#ifndef NANA_UNICODE + if(pos > str.size()) + pos = static_cast(str.size()); + const nana::char_t * pstr = str.c_str(); + if(pstr[pos] < 0) + { + bool incomp = false; + for(unsigned i = 0; i < pos; ++i) + { + if(pstr[i] < 0) + incomp = !incomp; + else + incomp = false; + } + return incomp; + } +#endif + return false; + } +} diff --git a/source/detail/linux_X11/platform_spec.cpp b/source/detail/linux_X11/platform_spec.cpp new file mode 100644 index 00000000..38301911 --- /dev/null +++ b/source/detail/linux_X11/platform_spec.cpp @@ -0,0 +1,1330 @@ +/* + * Platform Specification Implementation + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Nana Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://nanapro.org/LICENSE_1_0.txt) + * + * @file: nana/detail/linux_X11/platform_spec.cpp + * + * This file provides basis class and data structrue that required by nana + * + * http://standards.freedesktop.org/clipboards-spec/clipboards-0.1.txt + */ +#include + +#include PLATFORM_SPEC_HPP +#include +#include +#include +#include +#include +#include +#include +#include GUI_BEDROCK_HPP +#include +#include +#include +#include + +namespace nana +{ +namespace detail +{ + typedef native_window_type native_window_type; +#if defined(NANA_UNICODE) + //class conf + conf::conf(const char * file) + { + ifs_.open(file); + } + + bool conf::open(const char* file) + { + ifs_.open(file); + return static_cast(ifs_ != 0); + } + + std::string conf::value(const char* key) + { + if((0 == key) || !ifs_) return ""; + size_t len = ::strlen(key); + ifs_.seekg(0, std::ios::beg); + ifs_.clear(); + std::string str; + + while(ifs_.good()) + { + std::getline(ifs_, str); + if(str.size() <= len + 1) + continue; + + size_t kpos = str.find(key); + if((kpos != str.npos) && ((kpos == 0) || (str.substr(0, kpos) == std::string(kpos, ' ')))) + { + size_t aspos = str.find("=", kpos + len); + if(aspos != str.npos) + { + if((aspos == kpos + len) || (str.substr(kpos + len, aspos) == std::string(aspos - kpos - len, ' '))) + { + std::string res = str.substr(aspos + 1); + size_t beg = res.find_first_not_of(" "); + if(beg && (beg != res.npos)) + res = res.substr(beg); + beg = res.find("\""); + if(beg == 0) + { + size_t end = res.find_last_of("\""); + if(beg != end) + return res.substr(beg + 1, (end == res.npos ? res.npos : (end - 1))); + } + return res; + } + } + } + } + return std::string(); + } + //end class conf + + //class charset_conv + charset_conv::charset_conv(const char* tocode, const char* fromcode) + { + handle_ = ::iconv_open(tocode, fromcode); + } + + charset_conv::~charset_conv() + { + ::iconv_close(handle_); + } + + std::string charset_conv::charset(const std::string& str) const + { + if(reinterpret_cast(-1) == handle_) + return std::string(); + + char * inbuf = const_cast(str.c_str()); + std::size_t inleft = str.size(); + std::size_t outlen = (inleft * 4 + 4); + char * strbuf = new char[outlen + 4]; + char * outbuf = strbuf; + std::size_t outleft = outlen; + ::iconv(handle_, &inbuf, &inleft, &outbuf, &outleft); + std::string rstr(strbuf, outbuf); + delete [] strbuf; + return rstr; + } + + std::string charset_conv::charset(const char* buf, std::size_t len) const + { + if(reinterpret_cast(-1) == handle_) + return std::string(); + + char * inbuf = const_cast(buf); + std::size_t outlen = (len * 4 + 4); + char * strbuf = new char[outlen + 4]; + char * outbuf = strbuf; + std::size_t outleft = outlen; + ::iconv(handle_, &inbuf, &len, &outbuf, &outleft); + std::string rstr(strbuf, outbuf); + delete [] strbuf; + return rstr; + } + //end class charset_conv +#endif + + struct caret_tag + { + native_window_type window; + bool has_input_method_focus; + bool visible; + nana::point pos; + nana::size size; + nana::rectangle rev; + nana::paint::graphics graph; + nana::paint::graphics rev_graph; + XIM input_method; + XIC input_context; + XFontSet input_font; + XRectangle input_spot; + XRectangle input_status_area; + long input_context_event_mask; + + caret_tag(native_window_type wd) + : window(wd), has_input_method_focus(false), visible(false), input_method(0), input_context(0), input_font(0), input_context_event_mask(0) + {} + }; + + class timer_runner + { + typedef void (*timer_proc_t)(std::size_t id); + + struct timer_tag + { + std::size_t id; + unsigned tid; + std::size_t interval; + std::size_t timestamp; + timer_proc_t proc; + }; + + //timer_group + //It owns a set of timers' identifier, and a container for the delay deletion + //The delay delection is used for storing a timer id when the timer is deleted in a timer's + //event handler function. If the timer is deleted directly in timer's event handler function, + //it will cause a crash because the deletion operation invalidates iterator. + //According to ISO C++ 2011, 23.2.4 9 the erase members shall invalidate only iterators and + //references to the erased elements(timer_group::timers is an associative container), + //although the iterator can be moved to next before calling the timer handler function, the delay + //deletion is still required. Becuase a timer which is erased in another timer's handler function + //happens to be refereneced by the "next" iterator. + struct timer_group + { + bool proc_entered{false}; //This flag indicates whether the timers are going to do event. + std::set timers; + std::vector delay_deleted; + }; + public: + timer_runner() + : is_proc_handling_(false) + {} + + void set(std::size_t id, std::size_t interval, timer_proc_t proc) + { + auto i = holder_.find(id); + if(i != holder_.end()) + { + i->second.interval = interval; + i->second.proc = proc; + return; + } + unsigned tid = nana::system::this_thread_id(); + threadmap_[tid].timers.insert(id); + + timer_tag & tag = holder_[id]; + tag.id = id; + tag.tid = tid; + tag.interval = interval; + tag.timestamp = 0; + tag.proc = proc; + } + + bool is_proc_handling() const + { + return is_proc_handling_; + } + + void kill(std::size_t id) + { + auto i = holder_.find(id); + if(i != holder_.end()) + { + auto tid = i->second.tid; + + auto ig = threadmap_.find(tid); + if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_ + { + auto & group = ig->second; + if(!group.proc_entered) + { + group.timers.erase(id); + if(group.timers.empty()) + threadmap_.erase(ig); + } + else + group.delay_deleted.push_back(id); + } + holder_.erase(i); + } + } + + bool empty() const + { + return (holder_.empty()); + } + + void timer_proc(unsigned tid) + { + is_proc_handling_ = true; + auto i = threadmap_.find(tid); + if(i != threadmap_.end()) + { + auto & group = i->second; + group.proc_entered = true; + unsigned ticks = nana::system::timestamp(); + for(auto timer_id : group.timers) + { + auto & tag = holder_[timer_id]; + if(tag.timestamp) + { + if(ticks >= tag.timestamp + tag.interval) + { + tag.timestamp = ticks; + try + { + tag.proc(tag.id); + }catch(...){} //nothrow + } + } + else + tag.timestamp = ticks; + } + group.proc_entered = false; + for(auto tmr: group.delay_deleted) + group.timers.erase(tmr); + } + is_proc_handling_ = false; + } + private: + bool is_proc_handling_; + std::map threadmap_; + std::map holder_; + }; + + drawable_impl_type::drawable_impl_type() + : fgcolor_(0xFFFFFFFF) + { + string.tab_length = 4; + string.tab_pixels = 0; + string.whitespace_pixels = 0; +#if defined(NANA_UNICODE) + xftdraw = 0; + conv_.handle = ::iconv_open("UTF-8", "UTF-32"); + conv_.code = "UTF-32"; +#endif + } + + drawable_impl_type::~drawable_impl_type() + { +#if defined(NANA_UNICODE) + ::iconv_close(conv_.handle); +#endif + } + + void drawable_impl_type::fgcolor(unsigned color) + { + if(color != fgcolor_) + { + auto & spec = nana::detail::platform_spec::instance(); + platform_scope_guard psg; + + fgcolor_ = color; + switch(spec.screen_depth()) + { + case 16: + color = ((((color >> 16) & 0xFF) * 31 / 255) << 11) | + ((((color >> 8) & 0xFF) * 63 / 255) << 5) | + (color & 0xFF) * 31 / 255; + break; + } + ::XSetForeground(spec.open_display(), context, color); + ::XSetBackground(spec.open_display(), context, color); +#if defined(NANA_UNICODE) + xft_fgcolor.color.red = ((0xFF0000 & color) >> 16) * 0x101; + xft_fgcolor.color.green = ((0xFF00 & color) >> 8) * 0x101; + xft_fgcolor.color.blue = (0xFF & color) * 0x101; + xft_fgcolor.color.alpha = 0xFFFF; +#endif + } + } + + class font_deleter + { + public: + void operator()(const font_tag* fp) const + { + if(fp && fp->handle) + { + platform_scope_guard psg; +#if defined(NANA_UNICODE) + ::XftFontClose(nana::detail::platform_spec::instance().open_display(), fp->handle); +#else + ::XFreeFontSet(nana::detail::platform_spec::instance().open_display(), fp->handle); +#endif + } + delete fp; + } + };//end class font_deleter + + platform_scope_guard::platform_scope_guard() + { + platform_spec::instance().lock_xlib(); + } + + platform_scope_guard::~platform_scope_guard() + { + platform_spec::instance().unlock_xlib(); + } + + int X11_error_handler(Display* disp, XErrorEvent* err) + { + platform_spec::instance().error_code = err->error_code; + return 0; + } + + int X11_fatal_handler(Display* disp) + { + return 0; + } + + platform_spec::timer_runner_tag::timer_runner_tag() + : runner(0), delete_declared(false) + {} + + platform_spec::platform_spec() + :display_(0), colormap_(0), def_X11_error_handler_(0), grab_(0) + { + ::XInitThreads(); + const char * langstr = getenv("LC_CTYPE"); + if(0 == langstr) + { + langstr = getenv("LC_ALL"); + } + + std::string langstr_dup; + if(langstr) + { + langstr_dup = langstr; + auto dotpos = langstr_dup.find("."); + if(dotpos != langstr_dup.npos) + { + auto beg = langstr_dup.begin() + dotpos + 1; + std::transform(beg, langstr_dup.end(), beg, toupper); + } + } + else + langstr_dup = "zh_CN.UTF-8"; + std::setlocale(LC_CTYPE, langstr_dup.c_str()); + if(::XSupportsLocale()) + ::XSetLocaleModifiers(langstr_dup.c_str()); + + + display_ = ::XOpenDisplay(0); + colormap_ = DefaultColormap(display_, ::XDefaultScreen(display_)); + + //Initialize the member data + selection_.content.utf8_string = 0; + xdnd_.good_type = None; + + atombase_.wm_protocols = ::XInternAtom(display_, "WM_PROTOCOLS", False); + atombase_.wm_change_state = ::XInternAtom(display_, "WM_CHANGE_STATE", False); + atombase_.wm_delete_window = ::XInternAtom(display_, "WM_DELETE_WINDOW", False); + atombase_.net_wm_state = ::XInternAtom(display_, "_NET_WM_STATE", False); + atombase_.net_wm_state_skip_taskbar = ::XInternAtom(display_, "_NET_WM_STATE_SKIP_TASKBAR", False); + atombase_.net_wm_state_fullscreen = ::XInternAtom(display_, "_NET_WM_STATE_FULLSCREEN", False); + atombase_.net_wm_state_maximized_horz = ::XInternAtom(display_, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + atombase_.net_wm_state_maximized_vert = ::XInternAtom(display_, "_NET_WM_STATE_MAXIMIZED_VERT", False); + atombase_.net_wm_state_modal = ::XInternAtom(display_, "_NET_WM_STATE_MODAL", False); + atombase_.net_wm_window_type = ::XInternAtom(display_, "_NET_WM_WINDOW_TYPE", False); + atombase_.net_wm_window_type_normal = ::XInternAtom(display_, "_NET_WM_WINDOW_TYPE_NORMAL", False); + atombase_.net_wm_window_type_utility = ::XInternAtom(display_, "_NET_WM_WINDOW_TYPE_UTILITY", False); + atombase_.net_wm_window_type_dialog = ::XInternAtom(display_, "_NET_WM_WINDOW_TYPE_DIALOG", False); + atombase_.motif_wm_hints = ::XInternAtom(display_, "_MOTIF_WM_HINTS", False); + + atombase_.clipboard = ::XInternAtom(display_, "CLIPBOARD", True); + atombase_.text = ::XInternAtom(display_, "TEXT", True); + atombase_.text_uri_list = ::XInternAtom(display_, "text/uri-list", True); + atombase_.utf8_string = ::XInternAtom(display_, "UTF8_STRING", True); + atombase_.targets = ::XInternAtom(display_, "TARGETS", True); + + atombase_.xdnd_aware = ::XInternAtom(display_, "XdndAware", False); + atombase_.xdnd_enter = ::XInternAtom(display_, "XdndEnter", False); + atombase_.xdnd_position = ::XInternAtom(display_, "XdndPosition", False); + atombase_.xdnd_status = ::XInternAtom(display_, "XdndStatus", False); + atombase_.xdnd_action_copy = ::XInternAtom(display_, "XdndActionCopy", False); + atombase_.xdnd_drop = ::XInternAtom(display_, "XdndDrop", False); + atombase_.xdnd_selection = ::XInternAtom(display_, "XdndSelection", False); + atombase_.xdnd_typelist = ::XInternAtom(display_, "XdndTypeList", False); + atombase_.xdnd_finished = ::XInternAtom(display_, "XdndFinished", False); + + //Create default font object. + def_font_ptr_ = make_native_font(0, font_size_to_height(10), 400, false, false, false); + msg_dispatcher_ = new msg_dispatcher(display_); + } + + platform_spec::~platform_spec() + { + delete msg_dispatcher_; + + //The font should be destroyed before closing display, + //otherwise it crashs + def_font_ptr_.reset(); + + close_display(); + } + + const platform_spec::font_ptr_t& platform_spec::default_native_font() const + { + return def_font_ptr_; + } + + void platform_spec::default_native_font(const font_ptr_t& fp) + { + def_font_ptr_ = fp; + } + + unsigned platform_spec::font_size_to_height(unsigned size) const + { + return size; + } + + unsigned platform_spec::font_height_to_size(unsigned height) const + { + return height; + } + + platform_spec::font_ptr_t platform_spec::make_native_font(const nana::char_t* name, unsigned height, unsigned weight, bool italic, bool underline, bool strike_out) + { + font_ptr_t ref; +#if defined(NANA_UNICODE) + if(0 == name || *name == 0) + name = STR("*"); + + std::string nmstr = nana::charset(name); + XftFont* handle = 0; + std::stringstream ss; + ss<(basestr.c_str()), &missing_list, &missing_count, &defstr); +#endif + if(handle) + { + font_tag * impl = new font_tag; + impl->name = name; + impl->height = height; + impl->weight = weight; + impl->italic = italic; + impl->underline = underline; + impl->strikeout = strike_out; + impl->handle = handle; + return font_ptr_t(impl, font_deleter()); + } + return font_ptr_t(); + } + + Display* platform_spec::open_display() + { + return display_; + } + + void platform_spec::close_display() + { + if(display_) + { + ::XSync(reinterpret_cast(display_), true); + ::XCloseDisplay(reinterpret_cast(display_)); + display_ = 0; + } + } + + void platform_spec::lock_xlib() + { + xlib_locker_.lock(); + } + + void platform_spec::unlock_xlib() + { + xlib_locker_.unlock(); + } + + Window platform_spec::root_window() + { + return ::XDefaultRootWindow(reinterpret_cast(display_)); + } + + int platform_spec::screen_depth() + { + return ::XDefaultDepth(display_, ::XDefaultScreen(display_)); + } + + Visual* platform_spec::screen_visual() + { + return ::XDefaultVisual(display_, ::XDefaultScreen(display_)); + } + + Colormap& platform_spec::colormap() + { + return colormap_; + } + + platform_spec& platform_spec::instance() + { + static platform_spec object; + return object; + } + + const atombase_tag& platform_spec::atombase() const + { + return atombase_; + } + + //There are three members make_owner(), get_owner() and remove(), + //they are maintain a table to discribe the owner of windows because the feature in X11, the + //owner of top level window must be RootWindow. + void platform_spec::make_owner(native_window_type owner, native_window_type wd) + { + platform_scope_guard psg; + wincontext_[wd].owner = owner; + window_context_t & context = wincontext_[owner]; + if(context.owned == 0) + context.owned = new std::vector; + context.owned->push_back(wd); + } + + native_window_type platform_spec::get_owner(native_window_type wd) const + { + platform_scope_guard psg; + auto i = wincontext_.find(wd); + return (i != wincontext_.end() ? i->second.owner : nullptr); + } + + void platform_spec::remove(native_window_type wd) + { + msg_dispatcher_->erase(reinterpret_cast(wd)); + platform_scope_guard psg; + auto i = wincontext_.find(wd); + if(i == wincontext_.end()) return; + + if(i->second.owner) + { + auto u = wincontext_.find(i->second.owner); + if(u != wincontext_.end()) + { + auto * vec = u->second.owned; + if(vec) + { + auto j = std::find(vec->begin(), vec->end(), i->first); + if(j != vec->end()) + vec->erase(j); + } + } + } + + auto * vec = i->second.owned; + if(vec) + { + set_error_handler(); + auto & wd_manager = detail::bedrock::instance().wd_manager; + for(auto u = vec->rbegin(); u != vec->rend(); ++u) + wd_manager.close(wd_manager.root(*u)); + + rev_error_handler(); + } + delete vec; + wincontext_.erase(i); + iconbase_.erase(wd); + } + + + void platform_spec::write_keystate(const XKeyEvent& xkey) + { + this->key_state_ = xkey; + } + + void platform_spec::read_keystate(XKeyEvent& xkey) + { + xkey = this->key_state_; + } + + XIC platform_spec::caret_input_context(native_window_type wd) const + { + platform_scope_guard psg; + auto i = caret_holder_.carets.find(wd); + if(i != caret_holder_.carets.end()) + return i->second->input_context; + return 0; + } + + void platform_spec::caret_open(native_window_type wd, unsigned width, unsigned height) + { + bool is_start_routine = false; + platform_scope_guard psg; + caret_tag * & addr = caret_holder_.carets[wd]; + if(0 == addr) + { + addr = new caret_tag(wd); + is_start_routine = (caret_holder_.carets.size() == 1); + addr->input_method = ::XOpenIM(display_, 0, 0, 0); + if(addr->input_method) + { + XIMStyles* imstyle; + ::XGetIMValues(addr->input_method, XNQueryInputStyle, &imstyle, nullptr, nullptr); + if(imstyle) + { + if(imstyle->count_styles) + { + addr->input_font = 0; + XVaNestedList preedit_attr = ::XVaCreateNestedList(0, XNSpotLocation, &(addr->input_spot), nullptr); + XVaNestedList status_attr = ::XVaCreateNestedList(0, XNAreaNeeded, &(addr->input_status_area), nullptr); + XIMStyle * style_end = imstyle->supported_styles + imstyle->count_styles; + bool has_status = false; + bool has_preedit = false; + for(XIMStyle * i = imstyle->supported_styles; i != style_end; ++i) + { + if(*i == (XIMPreeditPosition | XIMStatusArea)) + { + has_status = has_preedit = true; + break; + } + else if(*i == (XIMPreeditPosition | XIMStatusNothing)) + has_preedit = true; + } + + if(has_status) + { + addr->input_context = ::XCreateIC(addr->input_method, XNInputStyle, (XIMPreeditPosition | XIMStatusArea), + XNPreeditAttributes, preedit_attr, XNStatusAttributes, status_attr, + XNClientWindow, reinterpret_cast(wd), nullptr); + } + else + addr->input_context = 0; + + if((addr->input_context == 0) && has_preedit) + { + addr->input_context = ::XCreateIC(addr->input_method, XNInputStyle, (XIMPreeditPosition | XIMStatusNothing), + XNPreeditAttributes, preedit_attr, XNClientWindow, reinterpret_cast(wd), nullptr); + } + + if(addr->input_context) + { + XVaNestedList attr = ::XVaCreateNestedList(0, XNAreaNeeded, &(addr->input_status_area), XNClientWindow, reinterpret_cast(wd), nullptr); + ::XGetICValues(addr->input_context, XNStatusAttributes, attr, nullptr); + ::XFree(attr); + } + else + addr->input_context = ::XCreateIC(addr->input_method, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), + XNClientWindow, reinterpret_cast(wd), nullptr); + + if(addr->input_context) + { + //Make the IM event filter. + ::XGetICValues(addr->input_context, XNFilterEvents, &(addr->input_context_event_mask), nullptr); + XWindowAttributes attr; + ::XGetWindowAttributes(display_, reinterpret_cast(wd), &attr); + XSetWindowAttributes new_attr; + new_attr.event_mask = (attr.your_event_mask | addr->input_context_event_mask); + ::XChangeWindowAttributes(display_, reinterpret_cast(wd), CWEventMask, &new_attr); + } + ::XFree(preedit_attr); + ::XFree(status_attr); + } + ::XFree(imstyle); + } + } + } + + addr->visible = false; + addr->graph.make(width, height); + addr->graph.rectangle(0x0, true); + addr->rev_graph.make(width, height); + + addr->size.width = width; + addr->size.height = height; + + if(addr->input_context && (false == addr->has_input_method_focus)) + { + ::XSetICFocus(addr->input_context); + addr->has_input_method_focus = true; + } + + if(is_start_routine) + { + caret_holder_.exit_thread = false; + auto fn = [this](){ this->_m_caret_routine(); }; + caret_holder_.thr.reset(new std::thread(fn)); + } + } + + void platform_spec::caret_close(native_window_type wd) + { + bool is_end_routine = false; + { + platform_scope_guard psg; + + auto i = caret_holder_.carets.find(wd); + if(i != caret_holder_.carets.end()) + { + caret_tag * addr = i->second; + if(addr->input_context) + { + if(addr->has_input_method_focus) + { + ::XUnsetICFocus(addr->input_context); + addr->has_input_method_focus = false; + } + + //Remove the IM event filter. + set_error_handler(); + XWindowAttributes attr; + if(BadWindow != ::XGetWindowAttributes(display_, reinterpret_cast(wd), &attr)) + { + if((attr.your_event_mask & addr->input_context_event_mask) == addr->input_context_event_mask) + { + XSetWindowAttributes new_attr; + new_attr.event_mask = (attr.your_event_mask & ~addr->input_context_event_mask); + ::XChangeWindowAttributes(display_, reinterpret_cast(wd), CWEventMask, &new_attr); + } + } + rev_error_handler(); + + ::XDestroyIC(addr->input_context); + } + + if(addr->input_font) + ::XFreeFontSet(display_, addr->input_font); + + if(addr->input_method) + ::XCloseIM(addr->input_method); + + delete i->second; + caret_holder_.carets.erase(i); + + } + + is_end_routine = (caret_holder_.carets.size() == 0); + } + + if(is_end_routine && (caret_holder_.thr != nullptr) && (caret_holder_.thr->joinable())) + { + caret_holder_.exit_thread = true; + caret_holder_.thr->join(); + caret_holder_.thr.reset(); + } + } + + void platform_spec::caret_pos(native_window_type wd, int x, int y) + { + platform_scope_guard psg; + auto i = caret_holder_.carets.find(wd); + if(i != caret_holder_.carets.end()) + { + caret_tag & crt = *i->second; + caret_reinstate(crt); + crt.pos.x = x; + crt.pos.y = y; + } + } + + void platform_spec::caret_visible(native_window_type wd, bool vis) + { + platform_scope_guard psg; + auto i = caret_holder_.carets.find(wd); + if(i != caret_holder_.carets.end()) + { + caret_tag& crt = *i->second; + if(crt.visible != vis) + { + if(vis == false) + { + caret_reinstate(crt); + if(crt.input_context && crt.has_input_method_focus) + { + ::XUnsetICFocus(crt.input_context); + crt.has_input_method_focus = false; + } + } + else + { + if(crt.input_context && (false == crt.has_input_method_focus)) + { + ::XSetICFocus(crt.input_context); + crt.has_input_method_focus = true; + } + } + crt.visible = vis; + } + } + } + + void platform_spec::caret_flash(caret_tag & crt) + { + if(crt.visible && (false == caret_reinstate(crt))) + { + crt.rev_graph.bitblt(crt.size, crt.window, crt.pos); + crt.rev.width = crt.size.width; + crt.rev.height = crt.size.height; + crt.rev.x = crt.pos.x; + crt.rev.y = crt.pos.y; + crt.graph.paste(crt.window, crt.rev, 0, 0); + } + } + + bool platform_spec::caret_update(native_window_type wd, nana::paint::graphics& root_graph, bool is_erase_caret_from_root_graph) + { + platform_scope_guard psg; + auto i = caret_holder_.carets.find(wd); + if(i != caret_holder_.carets.end()) + { + caret_tag & crt = *i->second; + if(is_erase_caret_from_root_graph) + { + root_graph.bitblt(crt.rev, crt.rev_graph); + } + else + { + bool owns_caret = false; + nana::paint::graphics * crt_graph; + if(crt.rev.width && crt.rev.height) + { + crt.rev_graph.bitblt(crt.size, root_graph, crt.pos); + crt_graph = &crt.graph; + owns_caret = true; + } + else + crt_graph = &crt.rev_graph; + + root_graph.bitblt(crt.rev, *crt_graph); + return owns_caret; + } + } + return false; + } + + //Copy the reversed graphics to the window + bool platform_spec::caret_reinstate(caret_tag& crt) + { + if(crt.rev.width && crt.rev.height) + { + crt.rev_graph.paste(crt.window, crt.rev, 0, 0); + //Drop the reversed graphics in order to draw the + //caret in the next flash. + crt.rev.width = crt.rev.height = 0; + return true; + } + return false; + } + + void platform_spec::set_error_handler() + { + platform_scope_guard psg; + error_code = 0; + def_X11_error_handler_ = ::XSetErrorHandler(X11_error_handler); + } + + int platform_spec::rev_error_handler() + { + if(def_X11_error_handler_) + { + platform_scope_guard psg; + ::XSync(display_, False); + ::XSetErrorHandler(def_X11_error_handler_); + } + return error_code; + } + + void platform_spec::_m_caret_routine() + { + while(false == caret_holder_.exit_thread) + { + if(xlib_locker_.try_lock()) + { + for(auto i : caret_holder_.carets) + caret_flash(*(i.second)); + + xlib_locker_.unlock(); + } + for(int i = 0; i < 5 && (false == caret_holder_.exit_thread); ++i) + nana::system::sleep(100); + } + } + + Window platform_spec::grab(Window wd) + { + Window r = grab_; + grab_ = wd; + return r; + } + + void platform_spec::set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t)) + { + std::lock_guard lock(timer_.mutex); + if(0 == timer_.runner) + timer_.runner = new timer_runner; + timer_.runner->set(id, interval, timer_proc); + timer_.delete_declared = false; + } + + void platform_spec::kill_timer(std::size_t id) + { + if(timer_.runner == 0) return; + + std::lock_guard lock(timer_.mutex); + timer_.runner->kill(id); + if(timer_.runner->empty()) + { + if(timer_.runner->is_proc_handling() == false) + { + delete timer_.runner; + timer_.runner = 0; + } + else + timer_.delete_declared = true; + } + } + + void platform_spec::timer_proc(unsigned tid) + { + std::lock_guard lock(timer_.mutex); + if(timer_.runner) + { + timer_.runner->timer_proc(tid); + if(timer_.delete_declared) + { + delete timer_.runner; + timer_.runner = 0; + timer_.delete_declared = false; + } + } + } + + void platform_spec::msg_insert(native_window_type wd) + { + msg_dispatcher_->insert(reinterpret_cast(wd)); + } + + void platform_spec::msg_set(timer_proc_type tp, event_proc_type ep) + { + msg_dispatcher_->set(tp, ep, &platform_spec::_m_msg_filter); + } + + void platform_spec::msg_dispatch(native_window_type modal) + { + msg_dispatcher_->dispatch(reinterpret_cast(modal)); + } + + void* platform_spec::request_selection(native_window_type requestor, Atom type, size_t& size) + { + if(requestor) + { + Atom clipboard = atombase_.clipboard; + xlib_locker_.lock(); + Window owner = ::XGetSelectionOwner(display_, clipboard); + if(owner) + { + selection_tag::item_t * selim = new selection_tag::item_t; + selim->type = type; + selim->requestor = reinterpret_cast(requestor); + selim->buffer = nullptr; + selim->bufsize = 0; + + this->selection_.items.push_back(selim); + ::XConvertSelection(display_, clipboard, type, clipboard, + reinterpret_cast(requestor), CurrentTime); + ::XFlush(display_); + xlib_locker_.unlock(); + + std::unique_lockcond_mutex)> lock(selim->cond_mutex); + selim->cond.wait(lock); + + size = selim->bufsize; + void * retbuf = selim->buffer; + delete selim; + return retbuf; + } + else + xlib_locker_.unlock(); + } + return nullptr; + } + + void platform_spec::write_selection(native_window_type owner, Atom type, const void * buf, size_t bufsize) + { + platform_scope_guard psg; + ::XSetSelectionOwner(display_, atombase_.clipboard, reinterpret_cast(owner), CurrentTime); + ::XFlush(display_); + if(XA_STRING == type || atombase_.utf8_string == type) + { + std::string * utf8str = selection_.content.utf8_string; + if(utf8str) + utf8str->clear(); + else + utf8str = new std::string; + + utf8str->append(reinterpret_cast(buf), reinterpret_cast(buf) + bufsize); + selection_.content.utf8_string = utf8str; + } + } + + //Icon Storage + const nana::paint::graphics& platform_spec::keep_window_icon(native_window_type wd, const nana::paint::image& img) + { + nana::paint::graphics & graph = iconbase_[wd]; + graph.make(img.size().width, img.size().height); + img.paste(graph, 0, 0); + return graph; + } + + //_m_msg_filter + //@return: _m_msg_filter returns three states + // 0 = msg_dispatcher dispatches the XEvent + // 1 = msg_dispatcher dispatches the msg_packet_tag that modified by _m_msg_filter + // 2 = msg_dispatcher should ignore the msg, because the XEvent is processed by _m_msg_filter + int platform_spec::_m_msg_filter(XEvent& evt, msg_packet_tag& msg) + { + platform_spec & self = instance(); + if(SelectionNotify == evt.type) + { + if(evt.xselection.property) + { + Atom type; + int format; + unsigned long len, bytes_left = 0; + unsigned char *data; + + ::XGetWindowProperty(self.display_, evt.xselection.requestor, evt.xselection.property, 0, 0, 0, + AnyPropertyType, &type, &format, &len, &bytes_left, &data); + + if(evt.xselection.property == self.atombase_.clipboard) + { + platform_scope_guard psg; + + if(self.selection_.items.size()) + { + selection_tag::item_t * im = self.selection_.items.front(); + + if(bytes_left > 0 && (type == im->type)) + { + unsigned long dummy_bytes_left; + if(Success == ::XGetWindowProperty(self.display_, evt.xselection.requestor, + evt.xselection.property, 0, bytes_left, + 0, AnyPropertyType, &type, &format, &len, + &dummy_bytes_left, &data)) + { + im->buffer = data; + im->bufsize = len; + } + } + + + self.selection_.items.erase(self.selection_.items.begin()); + + std::lock_guardcond_mutex)> lock(im->cond_mutex); + im->cond.notify_one(); + + } + } + else if(evt.xselection.property == self.atombase_.xdnd_selection) + { + bool accepted = false; + msg.kind = msg.kind_mouse_drop; + msg.u.mouse_drop.window = 0; + if(bytes_left > 0 && type == self.xdnd_.good_type) + { + unsigned long dummy_bytes_left; + if(Success == ::XGetWindowProperty(self.display_, evt.xselection.requestor, + evt.xselection.property, 0, bytes_left, + 0, AnyPropertyType, &type, &format, &len, + &dummy_bytes_left, &data)) + { + std::vector * files = new std::vector; + std::stringstream ss(reinterpret_cast(data)); + while(true) + { + std::string file; + std::getline(ss, file); + if(false == ss.good()) break; + if(0 == file.find("file://")) + file = file.substr(7); + + while(file.size()) + { + auto ch = file.back(); + if('\r' == ch || '\n' == ch) + file.pop_back(); + else + break; + } + + files->push_back(nana::charset(file)); + } + if(files->size()) + { + msg.u.mouse_drop.window = evt.xselection.requestor; + msg.u.mouse_drop.x = self.xdnd_.pos.x; + msg.u.mouse_drop.y = self.xdnd_.pos.y; + msg.u.mouse_drop.files = files; + } + + accepted = true; + ::XFree(data); + } + } + XEvent respond; + ::memset(respond.xclient.data.l, 0, sizeof(respond.xclient.data.l)); + respond.xclient.display = self.display_; + respond.xclient.window = self.xdnd_.wd_src; + respond.xclient.message_type = self.atombase_.xdnd_finished; + respond.xclient.format = 32; + respond.xclient.data.l[0] = evt.xselection.requestor; + if(accepted) + { + respond.xclient.data.l[1] = 1; + respond.xclient.data.l[2] = self.atombase_.xdnd_action_copy; + } + ::XSendEvent(self.display_, self.xdnd_.wd_src, False, NoEventMask, &respond); + + if(msg.u.mouse_drop.window) + return 1; //Use the packet directly. + } + } + return 2; + } + else if(SelectionRequest == evt.type) + { + auto disp = evt.xselectionrequest.display; + XEvent respond; + + respond.xselection.property = evt.xselectionrequest.property; + if(self.atombase_.targets == evt.xselectionrequest.target) + { + std::vector atoms; + if(self.selection_.content.utf8_string) + { + atoms.push_back(self.atombase_.utf8_string); + atoms.push_back(XA_STRING); + } + + ::XChangeProperty(self.display_, evt.xselectionrequest.requestor, + evt.xselectionrequest.property, XA_ATOM, sizeof(Atom) * 8, 0, + reinterpret_cast(atoms.size() ? &atoms[0] : 0), static_cast(atoms.size())); + } + else if(XA_STRING == evt.xselectionrequest.target || self.atombase_.utf8_string == evt.xselectionrequest.target) + { + std::string str; + if(self.selection_.content.utf8_string) + str = *self.selection_.content.utf8_string; + + ::XChangeProperty(self.display_, evt.xselectionrequest.requestor, evt.xselectionrequest.property, evt.xselectionrequest.target, 8, 0, + reinterpret_cast(str.size() ? const_cast(str.c_str()) : 0), static_cast(str.size())); + } + else + respond.xselection.property = None; + + respond.xselection.type = SelectionNotify; + respond.xselection.display = disp; + respond.xselection.requestor = evt.xselectionrequest.requestor; + respond.xselection.selection = evt.xselectionrequest.selection; + respond.xselection.target = evt.xselectionrequest.target; + respond.xselection.time = evt.xselectionrequest.time; + + platform_scope_guard psg; + ::XSendEvent(disp, evt.xselectionrequest.requestor, 0, 0, &respond); + ::XFlush(disp); + return 2; + } + else if(ClientMessage == evt.type) + { + if(self.atombase_.xdnd_enter == evt.xclient.message_type) + { + const Atom * atoms = reinterpret_cast(&(evt.xclient.data.l[2])); + unsigned long len = 3; + unsigned char * data = 0; + self.xdnd_.wd_src = evt.xclient.data.l[0]; + + //Check whether there is more than three types. + if(evt.xclient.data.l[1] & 1) + { + Atom type; + int format; + unsigned long bytes_left; + ::XGetWindowProperty(self.display_, self.xdnd_.wd_src, self.atombase_.xdnd_typelist, 0, 0, False, + XA_ATOM, &type, &format, &len, &bytes_left, &data); + + if(bytes_left > 0) + { + ::XGetWindowProperty(self.display_, self.xdnd_.wd_src, self.atombase_.xdnd_typelist, + 0, bytes_left, False, XA_ATOM, + &type, &format, &len, &bytes_left, &data); + if(XA_ATOM == type && len > 0) + atoms = reinterpret_cast(data); + } + } + + self.xdnd_.good_type = None; + for(unsigned long i = 0; i < len; ++i) + { + if(atoms[i] == self.atombase_.text_uri_list) + { + self.xdnd_.good_type = self.atombase_.text_uri_list; + break; + } + } + + if(data) + ::XFree(data); + + return 2; + } + else if(self.atombase_.xdnd_position == evt.xclient.message_type) + { + Window wd_src = evt.xclient.data.l[0]; + int x = (evt.xclient.data.l[2] >> 16); + int y = (evt.xclient.data.l[2] & 0xFFFF); + + bool accepted = false; + //We have got the type what we want. + if(self.xdnd_.good_type != None) + { + Window child; + ::XTranslateCoordinates(self.display_, self.root_window(), evt.xclient.window, x, y, &self.xdnd_.pos.x, &self.xdnd_.pos.y, &child); + typedef detail::bedrock bedrock; + + auto wd = bedrock::instance().wd_manager.find_window(reinterpret_cast(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y); + if(wd && wd->flags.dropable) + { + accepted = true; + self.xdnd_.timestamp = evt.xclient.data.l[3]; + self.xdnd_.pos = wd->pos_root; + } + } + + XEvent respond; + memset(&respond, 0, sizeof respond); + respond.xany.type = ClientMessage; + respond.xany.display = self.display_; + respond.xclient.window = wd_src; + respond.xclient.message_type = self.atombase_.xdnd_status; + respond.xclient.format = 32; + + //Target window + respond.xclient.data.l[0] = evt.xclient.window; + //Accept set + respond.xclient.data.l[1] = (accepted ? 1 : 0); + respond.xclient.data.l[2] = 0; + respond.xclient.data.l[3] = 0; + respond.xclient.data.l[4] = self.atombase_.xdnd_action_copy; + + ::XSendEvent(self.display_, wd_src, True, NoEventMask, &respond); + return 2; + } + else if(self.atombase_.xdnd_drop == evt.xclient.message_type) + { + ::XConvertSelection(self.display_, self.atombase_.xdnd_selection, self.xdnd_.good_type, self.atombase_.xdnd_selection, + evt.xclient.window, self.xdnd_.timestamp); + //The XdndDrop should send a XdndFinished to source window. + //This operation is implemented in SelectionNotify, because + //XdndFinished should be sent after retrieving data. + return 2; + } + } + return 0; + } +}//end namespace detail +}//end namespace nana diff --git a/source/detail/platform_spec_selector.cpp b/source/detail/platform_spec_selector.cpp new file mode 100644 index 00000000..f3eeab01 --- /dev/null +++ b/source/detail/platform_spec_selector.cpp @@ -0,0 +1,22 @@ +/* + * Platform Specification Selector + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Nana Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://nanapro.org/LICENSE_1_0.txt) + * + * @file: nana/detail/platform_spec_selector.cpp + * + * This file is used to support the Nana project of some cross-platform IDE, + * + */ + +#include + +#if defined(NANA_WINDOWS) + #include "win32/platform_spec.cpp" +#elif defined(NANA_LINUX) + #include "linux_X11/platform_spec.cpp" +#endif + diff --git a/source/detail/win32/platform_spec.cpp b/source/detail/win32/platform_spec.cpp new file mode 100644 index 00000000..84ed07d4 --- /dev/null +++ b/source/detail/win32/platform_spec.cpp @@ -0,0 +1,246 @@ +/* + * Platform Specification Implementation + * Copyright(C) 2003-2013 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/detail/platform_spec.cpp + * + * This file provides basis class and data structrue that required by nana + */ +#include + +#include PLATFORM_SPEC_HPP +#include +#include + +namespace nana +{ +namespace detail +{ + drawable_impl_type::drawable_impl_type() + : pixbuf_ptr(nullptr), bytes_per_line(0), + fgcolor_(0xFFFFFFFF) + { + pen.handle = nullptr; + pen.color = nana::null_color; + pen.style = -1; + pen.width = -1; + + brush.handle = nullptr; + brush.style = brush_spec::Solid; + brush.color = nana::null_color; + + round_region.handle = nullptr; + round_region.radius_x = round_region.radius_y = 0; + + string.tab_length = 4; + string.tab_pixels = 0; + string.whitespace_pixels = 0; + } + + drawable_impl_type::~drawable_impl_type() + { + ::DeleteDC(context); + ::DeleteObject(pixmap); + ::DeleteObject(pen.handle); + ::DeleteObject(brush.handle); + ::DeleteObject(round_region.handle); + } + + void drawable_impl_type::fgcolor(nana::color_t col) + { + if(this->fgcolor_ != col) + { + ::SetTextColor(context, NANA_RGB(col)); + fgcolor_ = col; + } + } + + void drawable_impl_type::pen_spec::set(HDC context, int style, int width, nana::color_t color) + { + if(this->color != color || this->width != width || this->style != style) + { + this->color = color; + this->width = width; + this->style = style; + this->handle = ::CreatePen(style, width, NANA_RGB(color)); + ::DeleteObject(::SelectObject(context, this->handle)); + } + } + + void drawable_impl_type::brush_spec::set(HDC context, drawable_impl_type::brush_spec::t style, nana::color_t color) + { + if(this->color != color || this->style != style) + { + this->color = color; + this->style = style; + switch(style) + { + case brush_spec::HatchBDiagonal: + this->handle = ::CreateHatchBrush(HS_BDIAGONAL, NANA_RGB(color)); + break; + case brush_spec::Solid: + default: + this->style = brush_spec::Solid; + this->handle = ::CreateSolidBrush(NANA_RGB(color)); + break; + } + ::DeleteObject(::SelectObject(context, this->handle)); + } + } + + void drawable_impl_type::round_region_spec::set(const nana::rectangle& r, unsigned radius_x, unsigned radius_y) + { + if(this->r != r || this->radius_x != radius_x || this->radius_y != radius_y) + { + if(handle) + ::DeleteObject(this->handle); + this->r = r; + this->radius_x = radius_x; + this->radius_y = radius_y; + handle = ::CreateRoundRectRgn(r.x, r.y, r.x + static_cast(r.width) + 1, r.y + static_cast(r.height) + 1, static_cast(radius_x + 1), static_cast(radius_y + 1)); + } + } + + //struct font_tag::deleter + void font_tag::deleter::operator()(const font_tag* tag) const + { + if(tag && tag->handle) + ::DeleteObject(tag->handle); + delete tag; + } + //end struct font_tag::deleter + + //class platform_spec + platform_spec::co_initializer::co_initializer() + : ole32_(::LoadLibrary(STR("OLE32.DLL"))) + { + if(ole32_) + { + typedef HRESULT (__stdcall *CoInitializeEx_t)(LPVOID, DWORD); + CoInitializeEx_t fn_init = reinterpret_cast(::GetProcAddress(ole32_, "CoInitializeEx")); + if(0 == fn_init) + { + ::FreeLibrary(ole32_); + ole32_ = 0; + throw std::runtime_error("Nana.PlatformSpec.Co_initializer: Can't locate the CoInitializeEx()."); + } + else + fn_init(0, COINIT_APARTMENTTHREADED | /*COINIT_DISABLE_OLE1DDE =*/0x4); + } + else + throw std::runtime_error("Nana.PlatformSpec.Co_initializer: No Ole32.DLL Loaded."); + } + + platform_spec::co_initializer::~co_initializer() + { + if(ole32_) + { + typedef void (__stdcall *CoUninitialize_t)(void); + CoUninitialize_t fn_unin = reinterpret_cast(::GetProcAddress(ole32_, "CoUninitialize")); + if(fn_unin) + fn_unin(); + ::FreeLibrary(ole32_); + } + } + + platform_spec::platform_spec() + { + //Create default font object. + NONCLIENTMETRICS metrics = {}; + metrics.cbSize = sizeof metrics; +#if(WINVER >= 0x0600) + OSVERSIONINFO osvi = {}; + osvi.dwOSVersionInfoSize = sizeof(osvi); + ::GetVersionEx(&osvi); + if (osvi.dwMajorVersion < 6) + metrics.cbSize -= sizeof(metrics.iPaddedBorderWidth); +#endif + ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof metrics, &metrics, 0); + def_font_ptr_ = make_native_font(metrics.lfMessageFont.lfFaceName, font_size_to_height(9), 400, false, false, false); + } + + const platform_spec::font_ptr_t& platform_spec::default_native_font() const + { + return def_font_ptr_; + } + + void platform_spec::default_native_font(const font_ptr_t& fp) + { + def_font_ptr_ = fp; + } + + unsigned platform_spec::font_size_to_height(unsigned size) const + { + HDC hdc = ::GetDC(0); + size = ::MulDiv(int(size), ::GetDeviceCaps(hdc, LOGPIXELSY), 72); + ::ReleaseDC(0, hdc); + return size; + } + + unsigned platform_spec::font_height_to_size(unsigned height) const + { + HDC hdc = ::GetDC(0); + unsigned pixels = ::GetDeviceCaps(hdc, LOGPIXELSY); + ::ReleaseDC(0, hdc); + + height = static_cast(static_cast(72) * height / pixels); + return height; + } + + platform_spec::font_ptr_t platform_spec::make_native_font(const nana::char_t* name, unsigned height, unsigned weight, bool italic, bool underline, bool strike_out) + { + ::LOGFONT logfont; + memset(&logfont, 0, sizeof logfont); + + strcpy(logfont.lfFaceName, (name && *name ? name : def_font_ptr_->name.c_str())); + + logfont.lfCharSet = DEFAULT_CHARSET; + HDC hdc = ::GetDC(0); + logfont.lfHeight = -static_cast(height); + ::ReleaseDC(0, hdc); + + logfont.lfWidth = 0; + logfont.lfWeight = weight; + logfont.lfQuality = PROOF_QUALITY; + logfont.lfPitchAndFamily = FIXED_PITCH; + logfont.lfItalic = italic; + logfont.lfUnderline = underline; + logfont.lfStrikeOut = strike_out; + HFONT result = ::CreateFontIndirect(&logfont); + + if(result) + { + font_tag * impl = new font_tag; + impl->name = logfont.lfFaceName; + impl->height = height; + impl->weight = weight; + impl->italic = italic; + impl->underline = underline; + impl->strikeout = strike_out; + impl->handle = result; + return std::shared_ptr(impl, font_tag::deleter()); + } + return nullptr; + } + + platform_spec& platform_spec::instance() + { + static platform_spec object; + return object; + } + + void platform_spec::keep_window_icon(native_window_type wd, const paint::image& img) + { + iconbase_[wd] = img; + } + + void platform_spec::release_window_icon(native_window_type wd) + { + iconbase_.erase(wd); + } +}//end namespace detail +}//end namespace nana diff --git a/source/exceptions.cpp b/source/exceptions.cpp new file mode 100644 index 00000000..31c0a0b5 --- /dev/null +++ b/source/exceptions.cpp @@ -0,0 +1,71 @@ +/* + * Exception Definition + * Copyright(C) 2003-2013 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/exceptions.cpp + */ +#include + +namespace nana +{ + + //class thrd_exit + thrd_exit::thrd_exit(unsigned retval):retval_(retval){} + thrd_exit::~thrd_exit() throw(){} + const char* thrd_exit::what() const throw(){ return "Exit-Threading Exception"; } + unsigned thrd_exit::retval() const { return retval_; } + //end class thrd_exit + + //class bad_member + bad_member::bad_member(const std::string& what):what_(what){} + bad_member::~bad_member() throw(){} + const char* bad_member::what() const throw() + { + return what_.c_str(); + } + //end class bad_member + + //class bad_syntax + bad_syntax::bad_syntax(const std::string& what):what_(what){} + bad_syntax::~bad_syntax() throw(){} + const char* bad_syntax::what() const throw() + { + return what_.c_str(); + } + //end class bad_syntax + + //class bad_error + bad_error::bad_error(const std::string& what):what_(what){} + bad_error::~bad_error() throw(){} + const char* bad_error::what() const throw() + { + return what_.c_str(); + } + //end class bad_error + + //class bad_handle: public std::exception + bad_handle::bad_handle(const std::string& what):what_(what){} + bad_handle::~bad_handle() throw(){} + const char* bad_handle::what() const throw() + { + return what_.c_str(); + } + //end class bad_handle + + //class bad_window + bad_window::bad_window(const char* what) + :what_(what) + {} + + bad_window::~bad_window() throw(){} + + const char* bad_window::what() const throw() + { + return what_.c_str(); + } + //end class bad_window +} //end namespace nana diff --git a/source/filesystem/file_iterator.cpp b/source/filesystem/file_iterator.cpp new file mode 100644 index 00000000..d77900e1 --- /dev/null +++ b/source/filesystem/file_iterator.cpp @@ -0,0 +1,41 @@ +/* + * A File Iterator Implementation + * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)(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/filesystem/file_iterator.cpp + * @description: + * file_iterator is a toolkit for applying each file and directory in a + * specified path. + */ + +#include + +namespace nana +{ +namespace filesystem +{ + //struct fileinfo + fileinfo::fileinfo() + :size(0), directory(false) + {} +#if defined(NANA_WINDOWS) + fileinfo::fileinfo(const WIN32_FIND_DATA& wfd) + : name(wfd.cFileName), size(wfd.nFileSizeLow), + directory((FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY) + { + } +#elif defined(NANA_LINUX) + fileinfo::fileinfo(const nana::string& name, const struct stat& fst) + :name(name), size(fst.st_size), directory(0 != S_ISDIR(fst.st_mode)) + { + } +#endif + //end struct fileinfo + +}//end namespace filesystem +}//end namespace nana + diff --git a/source/filesystem/fs_utility.cpp b/source/filesystem/fs_utility.cpp new file mode 100644 index 00000000..d1f95e69 --- /dev/null +++ b/source/filesystem/fs_utility.cpp @@ -0,0 +1,443 @@ +/* + * A FileSystem Utility Implementation + * Copyright(C) 2003-2013 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/filesystem/fs_utility.cpp + * @description: + * provide some interface for file managment + */ + +#include +#include +#include +#if defined(NANA_WINDOWS) + #include + + #if defined(NANA_MINGW) + #ifndef _WIN32_IE + #define _WIN32_IE 0x0500 + #endif + #endif + + #include + #include +#elif defined(NANA_LINUX) + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace nana +{ +namespace filesystem +{ +//Because of No wide character version of POSIX +#if defined(NANA_LINUX) + typedef std::string string_t; + const char* splstr = "/\\"; +#else + typedef nana::string string_t; + const nana::char_t* splstr = STR("/\\"); +#endif + //class path + path::path(){} + + path::path(const nana::string& text) +#if defined(NANA_WINDOWS) + :text_(text) + { +#else + :text_(nana::charset(text)) + { +#endif + auto pos = text_.find_last_of(splstr); + for(; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) + text_.erase(pos); + } + + bool path::empty() const + { +#if defined(NANA_WINDOWS) + return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); +#elif defined(NANA_LINUX) + struct stat sta; + return (::stat(text_.c_str(), &sta) == -1); +#endif + } + + path path::root() const + { + #if defined(NANA_WINDOWS) + return path(filesystem::root(text_)); + #elif defined(NANA_LINUX) + return path(filesystem::root(nana::charset(text_))); + #endif + } + + int path::what() const + { +#if defined(NANA_WINDOWS) + unsigned long attr = ::GetFileAttributes(text_.c_str()); + if(INVALID_FILE_ATTRIBUTES == attr) + return type::not_exist; + + if(FILE_ATTRIBUTE_DIRECTORY & attr) + return type::directory; + + return type::file; +#elif defined(NANA_LINUX) + struct stat sta; + if(-1 == ::stat(text_.c_str(), &sta)) + return type::not_exist; + + if((S_IFDIR & sta.st_mode) == S_IFDIR) + return type::directory; + + if((S_IFREG & sta.st_mode) == S_IFREG) + return type::file; + + return type::not_exist; +#endif + } + + nana::string path::name() const + { + string_t::size_type pos = text_.find_last_of(splstr); +#if defined(NANA_WINDOWS) + return text_.substr(pos + 1); +#else + return nana::charset(text_.substr(pos + 1)); +#endif + } + //end class path + + namespace detail + { + //rm_dir_recursive + //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories + bool rm_dir_recursive(nana::string&& dir) + { + std::vector files; + nana::string path = dir; + path += '\\'; + + std::copy(file_iterator(dir), file_iterator(), std::back_inserter(files)); + + for(auto & f : files) + { + if(f.directory) + rm_dir_recursive(path + f.name); + else + rmfile((path + f.name).c_str()); + } + + return rmdir(dir.c_str(), true); + } + + bool mkdir_helper(const nana::string& dir, bool & if_exist) + { +#if defined(NANA_WINDOWS) + if(::CreateDirectory(dir.c_str(), 0)) + { + if_exist = false; + return true; + } + + if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); +#elif defined(NANA_LINUX) + if(0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) + { + if_exist = false; + return true; + } + + if_exist = (errno == EEXIST); +#endif + return false; + } + +#if defined(NANA_WINDOWS) + void filetime_to_c_tm(FILETIME& ft, struct tm& t) + { + FILETIME local_file_time; + if(::FileTimeToLocalFileTime(&ft, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + } + } +#endif + }//end namespace detail + + bool file_attrib(const nana::string& file, attribute& attr) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA fad; + if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) + { + LARGE_INTEGER li; + li.u.LowPart = fad.nFileSizeLow; + li.u.HighPart = fad.nFileSizeHigh; + attr.bytes = li.QuadPart; + attr.is_directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); + return true; + } +#elif defined(NANA_LINUX) + struct stat fst; + if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) + { + attr.bytes = fst.st_size; + attr.is_directory = (0 != (040000 & fst.st_mode)); + attr.modified = *(::localtime(&fst.st_ctime)); + return true; + } +#endif + return false; + } + + long long filesize(const nana::string& file) + { +#if defined(NANA_WINDOWS) + //Some compilation environment may fail to link to GetFileSizeEx + typedef BOOL (__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); + GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); + if(get_file_size_ex) + { + HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if(INVALID_HANDLE_VALUE != handle) + { + LARGE_INTEGER li; + if(!get_file_size_ex(handle, &li)) + li.QuadPart = 0; + + ::CloseHandle(handle); + return li.QuadPart; + } + } + return 0; +#elif defined(NANA_LINUX) + FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); + long long size = 0; + if(stream) + { + fseeko64(stream, 0, SEEK_END); + size = ftello64(stream); + fclose(stream); + } + return size; +#endif + } + + bool modified_file_time(const nana::string& file, struct tm& t) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA attr; + if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) + { + FILETIME local_file_time; + if(::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + return true; + } + } +#elif defined(NANA_LINUX) + struct stat attr; + if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) + { + t = *(::localtime(&attr.st_ctime)); + return true; + } +#endif + return false; + } + + bool mkdir(const nana::string& path, bool & if_exist) + { + if_exist = false; + if(path.size() == 0) return false; + + nana::string root; +#if defined(NANA_WINDOWS) + if(path.size() > 3 && path[1] == STR(':')) + root = path.substr(0, 3); +#elif defined(NANA_LINUX) + if(path[0] == STR('/')) + root = '/'; +#endif + bool mkstat = false; + std::size_t beg = root.size(); + + while(true) + { + beg = path.find_first_not_of(STR("/\\"), beg); + if(beg == path.npos) + break; + + std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); + if(pos != path.npos) + { + root += path.substr(beg, pos - beg); + + mkstat = detail::mkdir_helper(root, if_exist); + if(mkstat == false && if_exist == false) + return false; + +#if defined(NANA_WINDOWS) + root += STR('\\'); +#elif defined(NANA_LINUX) + root += STR('/'); +#endif + } + else + { + if(beg + 1 < path.size()) + { + root += path.substr(beg); + mkstat = detail::mkdir_helper(root, if_exist); + } + break; + } + beg = pos + 1; + } + return mkstat; + } + + bool rmfile(const nana::char_t* file) + { +#if defined(NANA_WINDOWS) + bool ret = false; + if(file) + { + ret = (::DeleteFile(file) == TRUE); + if(!ret) + ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); + } + + return ret; +#elif defined(NANA_LINUX) + if(std::remove(static_cast(nana::charset(file)).c_str())) + return (errno == ENOENT); + return true; +#endif + } + + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) + { + bool ret = false; + if(dir) + { +#if defined(NANA_WINDOWS) + ret = (::RemoveDirectory(dir) == TRUE); + if(!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) + ret = detail::rm_dir_recursive(dir); +#elif defined(NANA_LINUX) + std::string mbstr = nana::charset(dir); + if(::rmdir(mbstr.c_str())) + { + if(!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) + ret = detail::rm_dir_recursive(dir); + } + else + ret = true; +#endif + } + return ret; + } + + nana::string root(const nana::string& path) + { + std::size_t index = path.size(); + + if(index) + { + const nana::char_t * str = path.c_str(); + + for(--index; index > 0; --index) + { + nana::char_t c = str[index]; + if(c != '\\' && c != '/') + break; + } + + for(--index; index > 0; --index) + { + nana::char_t c = str[index]; + if(c == '\\' || c == '/') + break; + } + } + + return index?path.substr(0, index + 1):nana::string(); + } + + nana::string path_user() + { +#if defined(NANA_WINDOWS) + nana::char_t path[MAX_PATH]; + if(SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) + return path; +#elif defined(NANA_LINUX) + const char * s = ::getenv("HOME"); + if(s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + + nana::string path_current() + { +#if defined(NANA_WINDOWS) + nana::char_t buf[MAX_PATH]; + DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); + if(len) + { + if(len > MAX_PATH) + { + nana::char_t * p = new nana::char_t[len + 1]; + ::GetCurrentDirectory(len + 1, p); + nana::string s = p; + delete [] p; + return s; + } + return buf; + } +#elif defined(NANA_LINUX) + const char * s = ::getenv("PWD"); + if(s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } +}//end namespace filesystem +}//end namespace nana diff --git a/source/gui/animation.cpp b/source/gui/animation.cpp new file mode 100644 index 00000000..a8165470 --- /dev/null +++ b/source/gui/animation.cpp @@ -0,0 +1,642 @@ +/* + * An Animation Implementation + * Copyright(C) 2003-2013 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/gui/animation.cpp + */ + + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) + #include + #include + #include +#else + #include + #include + #include +#endif //NANA_MINGW + +namespace nana +{ + class animation; + + struct output_t + { + drawing::diehard_t diehard; + std::vector points; + + output_t() + : diehard(nullptr) + {} + }; + + struct framebuilder + { + std::size_t length; + std::function frbuilder; + + framebuilder(const std::function& f, std::size_t l) + : length(l), frbuilder(f) + {} + + framebuilder(std::size_t l, std::function&& f) + : length(l), frbuilder(std::move(f)) + {} + }; + + struct frame + { + enum class kind + { + oneshot, + framebuilder + }; + + frame(const paint::image& r) + : type(kind::oneshot) + { + u.oneshot = new paint::image(r); + } + + frame(paint::image&& r) + : type(kind::oneshot) + { + u.oneshot = new paint::image(std::move(r)); + } + + frame(const std::function& frbuilder, std::size_t length) + : type(kind::framebuilder) + { + u.frbuilder = new framebuilder(frbuilder, length); + } + + frame(std::function&& frbuilder, std::size_t length) + : type(kind::framebuilder) + { + u.frbuilder = new framebuilder(frbuilder, length); + } + + frame(const frame& r) + : type(r.type) + { + switch(type) + { + case kind::oneshot: + u.oneshot = new paint::image(*r.u.oneshot); + break; + case kind::framebuilder: + u.frbuilder = new framebuilder(*r.u.frbuilder); + break; + } + } + + frame(frame&& r) + : type(r.type) + { + u = r.u; + r.u.oneshot = nullptr; + } + + ~frame() + { + switch(type) + { + case kind::oneshot: + delete u.oneshot; + break; + case kind::framebuilder: + delete u.frbuilder; + break; + } + } + + frame& operator=(const frame& r) + { + if(this != &r) + { + switch(type) + { + case kind::oneshot: + delete u.oneshot; + break; + case kind::framebuilder: + delete u.frbuilder; + break; + } + + type = r.type; + switch(type) + { + case kind::oneshot: + u.oneshot = new paint::image(*r.u.oneshot); + break; + case kind::framebuilder: + u.frbuilder = new framebuilder(*r.u.frbuilder); + break; + } + } + return *this; + } + + frame& operator=(frame&& r) + { + if(this != &r) + { + switch(type) + { + case kind::oneshot: + delete u.oneshot; + break; + case kind::framebuilder: + delete u.frbuilder; + break; + } + + type = r.type; + u = r.u; + r.u.oneshot = nullptr; + } + return *this; + } + + std::size_t length() const + { + switch(type) + { + case kind::oneshot: + return 1; + case kind::framebuilder: + return u.frbuilder->length; + } + return 0; + } + + // + kind type; + union uframes + { + paint::image * oneshot; + framebuilder * frbuilder; + }u; + }; + + //class frameset + //struct frameset::impl + struct frameset::impl + { + //Only list whos iterator would not invalided after a insertion. + std::list frames; + std::list::iterator this_frame; + std::size_t pos_in_this_frame; + mutable bool good_frame_by_frmbuilder; //It indicates the state of frame whether is valid. + + impl() + : this_frame(frames.end()), pos_in_this_frame(0), + good_frame_by_frmbuilder(false) + {} + + //Render A frame on the set of windows. + void render_this(std::map& outs, paint::graphics& framegraph, nana::size& framegraph_dimension) const + { + if(this_frame == frames.end()) + return; + + frame & frmobj = *this_frame; + switch(frmobj.type) + { + case frame::kind::oneshot: + _m_render(outs, [&frmobj](paint::graphics& tar, const nana::point& pos) + { + frmobj.u.oneshot->paste(tar, pos.x, pos.y); + }); + break; + case frame::kind::framebuilder: + good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension); + if(good_frame_by_frmbuilder) + { + nana::rectangle r = framegraph_dimension; + _m_render(outs, [&r, &framegraph](paint::graphics& tar, const nana::point& pos) mutable + { + r.x = pos.x; + r.y = pos.y; + tar.bitblt(r, framegraph); + }); + } + break; + } + } + + //Render a frame on a specified window graph + void render_this(paint::graphics& graph, const nana::point& pos, paint::graphics& framegraph, nana::size& framegraph_dimension, bool rebuild_frame) const + { + if(this_frame == frames.end()) + return; + + frame & frmobj = *this_frame; + switch(frmobj.type) + { + case frame::kind::oneshot: + frmobj.u.oneshot->paste(graph, pos.x, pos.y); + break; + case frame::kind::framebuilder: + if(rebuild_frame) + good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension); + + if(good_frame_by_frmbuilder) + { + nana::rectangle r(pos, framegraph_dimension); + graph.bitblt(r, framegraph); + } + break; + } + } + + bool eof() const + { + return (frames.end() == this_frame); + } + + void next_frame() + { + if(frames.end() == this_frame) + return; + + frame & frmobj = *this_frame; + switch(frmobj.type) + { + case frame::kind::oneshot: + ++this_frame; + pos_in_this_frame = 0; + break; + case frame::kind::framebuilder: + if(pos_in_this_frame >= frmobj.u.frbuilder->length) + { + pos_in_this_frame = 0; + ++this_frame; + } + else + ++pos_in_this_frame; + break; + default: + throw std::runtime_error("Nana.GUI.Animation: Bad frame type"); + } + } + + //Seek to the first frame + void reset() + { + this_frame = frames.begin(); + pos_in_this_frame = 0; + } + private: + template + void _m_render(std::map& outs, Renderer renderer) const + { + for(auto & tar: outs) + { + auto graph = API::dev::window_graphics(tar.first); + if(nullptr == graph) + continue; + + for(auto & outp : tar.second.points) + renderer(*graph, outp); + + API::update_window(tar.first); + } + } + };//end struct frameset::impl + //public: + frameset::frameset() + : impl_(new impl) + {} + + void frameset::push_back(const paint::image& m) + { + bool located = impl_->this_frame != impl_->frames.end(); + impl_->frames.emplace_back(m); + if(false == located) + impl_->this_frame = impl_->frames.begin(); + } + + void frameset::push_back(paint::image&& m) + { + impl_->frames.emplace_back(std::move(m)); + if(1 == impl_->frames.size()) + impl_->this_frame = impl_->frames.begin(); + } + + void frameset::push_back(framebuilder&fb, std::size_t length) + { + impl_->frames.emplace_back(fb, length); + if(1 == impl_->frames.size()) + impl_->this_frame = impl_->frames.begin(); + } + + void frameset::push_back(framebuilder&& fb, std::size_t length) + { + impl_->frames.emplace_back(std::move(fb), length); + if(1 == impl_->frames.size()) + impl_->this_frame = impl_->frames.begin(); + } + //end class frameset + + //class animation + class animation::performance_manager + { + public: + struct thread_variable + { + std::mutex mutex; + std::condition_variable condvar; + std::vector animations; + + std::size_t active; //The number of active animations + std::shared_ptr thread; + double performance_parameter; + }; + + thread_variable * insert(impl* p); + void close(impl* p); + bool empty() const; + private: + void _m_perf_thread(thread_variable* thrvar); + private: + mutable std::recursive_mutex mutex_; + std::vector threads_; + }; //end class animation::performance_manager + + struct animation::impl + { + bool looped; + volatile bool paused; + + std::list framesets; + std::map branches; + std::map outputs; + + paint::graphics framegraph; //framegraph will be created by framebuilder + nana::size framegraph_dimension; + + struct state_t + { + std::list::iterator this_frameset; + }state; + + performance_manager::thread_variable * thr_variable; + static performance_manager * perf_manager; + + + impl() + : looped(false), paused(true) + { + state.this_frameset = framesets.begin(); + + { + nana::internal_scope_guard lock; + if(nullptr == perf_manager) + perf_manager = new performance_manager; + } + thr_variable = perf_manager->insert(this); + } + + ~impl() + { + perf_manager->close(this); + { + nana::internal_scope_guard lock; + if(perf_manager->empty()) + { + delete perf_manager; + perf_manager = nullptr; + } + } + } + + void render_this_specifically(paint::graphics& graph, const nana::point& pos) + { + if(state.this_frameset != framesets.end()) + state.this_frameset->impl_->render_this(graph, pos, framegraph, framegraph_dimension, false); + } + + void render_this_frame() + { + if(state.this_frameset != framesets.end()) + state.this_frameset->impl_->render_this(outputs, framegraph, framegraph_dimension); + } + + bool move_to_next() + { + if(state.this_frameset != framesets.end()) + { + state.this_frameset->impl_->next_frame(); + return (!state.this_frameset->impl_->eof()); + } + return false; + } + + //Seek to the first frameset + void reset() + { + state.this_frameset = framesets.begin(); + if(state.this_frameset != framesets.end()) + state.this_frameset->impl_->reset(); + } + };//end struct animation::impl + + //class animation::performance_manager + auto animation::performance_manager::insert(impl* p) -> thread_variable * + { + std::lock_guard lock(mutex_); + for(auto thr : threads_) + { + std::lock_guardmutex)> privlock(thr->mutex); + + if(thr->performance_parameter / (thr->animations.size() + 1) <= 43.3) + { + thr->animations.push_back(p); + return thr; + } + } + + auto thr = new thread_variable; + thr->animations.push_back(p); + thr->performance_parameter = 0.0; + thr->thread = std::make_shared([this, thr]() + { + _m_perf_thread(thr); + }); + + threads_.push_back(thr); + return thr; + } + + void animation::performance_manager::close(impl* p) + { + std::lock_guard lock(mutex_); + for(auto thr : threads_) + { + std::lock_guardmutex)> privlock(thr->mutex); + + auto i = std::find(thr->animations.begin(), thr->animations.end(), p); + if(i != thr->animations.end()) + { + thr->animations.erase(i); + return; + } + } + } + + bool animation::performance_manager::empty() const + { + std::lock_guard lock(mutex_); + for(auto thr : threads_) + { + if(thr->animations.size()) + return false; + } + return true; + } + + void animation::performance_manager::_m_perf_thread(thread_variable* thrvar) + { + nana::system::timepiece tmpiece; + while(true) + { + thrvar->active = 0; + tmpiece.start(); + + { + std::lock_guardmutex)> lock(thrvar->mutex); + for(auto ani : thrvar->animations) + { + if(ani->paused) + continue; + + ani->render_this_frame(); + if(false == ani->move_to_next()) + { + if(ani->looped) + { + ani->reset(); + ++thrvar->active; + } + } + else + ++thrvar->active; + } + } + + if(thrvar->active) + { + thrvar->performance_parameter = tmpiece.calc(); + if(thrvar->performance_parameter < 43.4) + nana::system::sleep(static_cast(43.4 - thrvar->performance_parameter)); + } + else + { + //There isn't an active frame, then let the thread + //wait for a signal for an active animation + std::unique_lock lock(thrvar->mutex); + if(0 == thrvar->active) + thrvar->condvar.wait(lock); + } + } + } + //end class animation::performance_manager + + animation::animation() + : impl_(new impl) + { + + } + + void animation::push_back(const frameset& frms) + { + impl_->framesets.emplace_back(frms); + if(1 == impl_->framesets.size()) + impl_->state.this_frameset = impl_->framesets.begin(); + } + /* + void branch(const std::string& name, const frameset& frms) + { + impl_->branches[name].frames = frms; + } + + void branch(const std::string& name, const frameset& frms, std::function condition) + { + auto & br = impl_->branches[name]; + br.frames = frms; + br.condition = condition; + } + */ + + void animation::looped(bool enable) + { + if(impl_->looped != enable) + { + impl_->looped = enable; + if(enable) + { + std::unique_lock lock(impl_->thr_variable->mutex); + if(0 == impl_->thr_variable->active) + { + impl_->thr_variable->active = 1; + impl_->thr_variable->condvar.notify_one(); + } + } + } + } + + void animation::play() + { + impl_->paused = false; + std::unique_lock lock(impl_->thr_variable->mutex); + if(0 == impl_->thr_variable->active) + { + impl_->thr_variable->active = 1; + impl_->thr_variable->condvar.notify_one(); + } + } + + void animation::pause() + { + impl_->paused = true; + } + + void animation::output(window wd, const nana::point& pos) + { + auto & output = impl_->outputs[wd]; + + if(nullptr == output.diehard) + { + drawing dw(wd); + output.diehard = dw.draw_diehard([this, pos](paint::graphics& tar){ + impl_->render_this_specifically(tar, pos); + }); + + API::events(wd).destroy.connect([this](const arg_destroy& arg){ + std::lock_guardthr_variable->mutex)> lock(impl_->thr_variable->mutex); + impl_->outputs.erase(arg.window_handle); + }); + } + output.points.push_back(pos); + } + //end class animation + + + animation::performance_manager * animation::impl::perf_manager; +} //end namespace nana + diff --git a/source/gui/basis.cpp b/source/gui/basis.cpp new file mode 100644 index 00000000..337d9291 --- /dev/null +++ b/source/gui/basis.cpp @@ -0,0 +1,33 @@ +/* + * Basis Implementation + * Copyright(C) 2003-2013 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/gui/basis.cpp + * + * This file provides basis class and data structrue that required by gui + */ + +#include + +namespace nana +{ + //struct appearance + //@brief: Window appearance structure + appearance::appearance() + :taskbar(true), floating(false), no_activate(false), + minimize(true), maximize(true), sizable(true), + decoration(true) + {} + + appearance::appearance(bool has_decorate, bool taskbar, bool is_float, bool no_activate, bool min, bool max, bool sizable) + : taskbar(taskbar), floating(is_float), no_activate(no_activate), + minimize(min), maximize(max), sizable(sizable), + decoration(has_decorate) + {} + //end struct appearance +}//end namespace nana + diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp new file mode 100644 index 00000000..6487eefb --- /dev/null +++ b/source/gui/detail/basic_window.cpp @@ -0,0 +1,385 @@ +#include +#include + +namespace nana +{ + namespace detail + { + //class caret_descriptor + caret_descriptor::caret_descriptor(core_window_t* wd, unsigned width, unsigned height) + :wd_(wd), size_(width, height), visible_(false), real_visible_state_(false), out_of_range_(false) + {} + + caret_descriptor::~caret_descriptor() + { + if(wd_) native_interface::caret_destroy(wd_->root); + } + + void caret_descriptor::set_active(bool active) + { + if(wd_) + { + if(active) + { + native_interface::caret_create(wd_->root, size_.width, size_.height); + real_visible_state_ = false; + visible_ = false; + this->position(point_.x, point_.y); + } + else + native_interface::caret_destroy(wd_->root); + + wd_->root_widget->other.attribute.root->ime_enabled = active; + } + } + + auto caret_descriptor::window() const ->core_window_t* + { + return wd_; + } + + void caret_descriptor::position(int x, int y) + { + point_.x = x; + point_.y = y; + + update(); + } + + void caret_descriptor::effective_range(nana::rectangle rect) + { + //Chech rect + if( (rect.width && rect.height) && + (rect.x + rect.width > 0) && + (rect.y + rect.height > 0)) + { + if(rect.x < 0) + { + rect.width += rect.x; + rect.x = 0; + } + + if(rect.y < 0) + { + rect.height += rect.y; + rect.y = 0; + } + + if(effective_range_ != rect) + { + effective_range_ = rect; + update(); + } + } + } + + nana::point caret_descriptor::position() const + { + return point_; + } + + void caret_descriptor::visible(bool isshow) + { + if(visible_ != isshow) + { + visible_ = isshow; + if(visible_ == false || false == out_of_range_) + _m_visible(isshow); + } + } + + bool caret_descriptor::visible() const + { + return visible_; + } + + nana::size caret_descriptor::size() const + { + return size_; + } + + void caret_descriptor::size(const nana::size& s) + { + size_ = s; + update(); + + if(visible_) this->visible(true); + } + + void caret_descriptor::_m_visible(bool isshow) + { + if(real_visible_state_ != isshow) + { + real_visible_state_ = isshow; + native_interface::caret_visible(wd_->root, isshow); + } + } + + void caret_descriptor::update() + { + nana::point pos = point_; + nana::size size = size_; + + nana::rectangle rect = effective_range_; + if(0 == effective_range_.width || 0 == effective_range_.height) + { + rect.x = rect.y = 0; + rect = wd_->dimension; + } + else + { + pos.x += effective_range_.x; + pos.y += effective_range_.y; + } + + if( (pos.x + static_cast(size.width) <= rect.x) || (pos.x >= rect.x + static_cast(rect.width)) || + (pos.y + static_cast(size.height) <= rect.y) || (pos.y >= rect.y + static_cast(rect.height)) + ) + {//Out of Range without overlap + if(false == out_of_range_) + { + out_of_range_ = true; + + if(visible_) + _m_visible(false); + } + } + else + { + if(pos.x < rect.x) + { + size.width -= (rect.x - pos.x); + pos.x = rect.x; + } + else if(pos.x + size.width > rect.x + rect.width) + { + size.width -= pos.x + size.width - (rect.x + rect.width); + } + + if(pos.y < rect.y) + { + size.width -= (rect.y - pos.y); + pos.y = rect.y; + } + else if(pos.y + size.height > rect.y + rect.height) + size.height -= pos.y + size.height - (rect.y + rect.height); + + if(out_of_range_) + { + if(paint_size_ == size) + _m_visible(true); + + out_of_range_ = false; + } + + if(paint_size_ != size) + { + native_interface::caret_destroy(wd_->root); + native_interface::caret_create(wd_->root, size.width, size.height); + real_visible_state_ = false; + if(visible_) + _m_visible(true); + + paint_size_ = size; + } + + native_interface::caret_pos(wd_->root, wd_->pos_root.x + pos.x, wd_->pos_root.y + pos.y); + } + } + //end class caret_descriptor + + //struct basic_window + //struct basic_window::other_tag + basic_window::other_tag::other_tag(category::flags categ) + : category(categ), active_window(nullptr), upd_state(update_state::none) + { + switch(categ) + { + case category::root_tag::value: + attribute.root = new attr_root_tag; + attribute.root->context.focus_changed = false; + break; + case category::frame_tag::value: + attribute.frame = new attr_frame_tag; + break; + default: + attribute.root = nullptr; + } + } + + basic_window::other_tag::~other_tag() + { + switch(category) + { + case category::root_tag::value: + delete attribute.root; + break; + case category::frame_tag::value: + delete attribute.frame; + break; + default: break; + } + } + //end struct basic_window::other_tag + + //basic_window + //@brief: constructor for the root window + basic_window::basic_window(basic_window* owner, widget* wdg, category::root_tag**) + : widget_ptr(wdg), other(category::root_tag::value) + { + drawer.bind(this); + _m_init_pos_and_size(0, rectangle()); + this->_m_initialize(owner); + } + + basic_window::~basic_window() + { + delete together.caret; + together.caret = nullptr; + + delete effect.bground; + effect.bground = nullptr; + } + + //bind_native_window + //@brief: bind a native window and baisc_window + void basic_window::bind_native_window(native_window_type wd, unsigned width, unsigned height, unsigned extra_width, unsigned extra_height, nana::paint::graphics& graphics) + { + if(category::root_tag::value == this->other.category) + { + this->root = wd; + dimension.width = width; + dimension.height = height; + this->extra_width = extra_width; + this->extra_height = extra_height; + this->root_widget = this; + this->root_graph = &graphics; + } + } + + void basic_window::frame_window(native_window_type wd) + { + if(category::frame_tag::value == this->other.category) + other.attribute.frame->container = wd; + } + + bool basic_window::is_ancestor_of(const basic_window* wd) const + { + while (wd) + { + if (this == wd->parent) + return true; + wd = wd->parent; + } + return false; + } + + bool basic_window::visible_parents() const + { + for (auto pnt = parent; pnt; pnt = pnt->parent) + { + if (!pnt->visible) + return false; + } + return true; + } + + bool basic_window::belong_to_lazy() const + { + for (auto wd = this; wd; wd = wd->parent) + { + if (basic_window::update_state::refresh == wd->other.upd_state) + return true; + } + return false; + } + + void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r) + { + pos_owner = pos_root = r; + dimension = r; + + if(parent) + { + pos_root.x += parent->pos_root.x; + pos_root.y += parent->pos_root.y; + } + } + + void basic_window::_m_initialize(basic_window* agrparent) + { + if(other.category == category::root_tag::value) + { + if(agrparent && (nana::system::this_thread_id() != agrparent->thread_id)) + agrparent = nullptr; + + while(agrparent && (agrparent->other.category != category::root_tag::value)) + agrparent = agrparent->parent; + + owner = agrparent; + parent = nullptr; + index = 0; + } + else + { + parent = agrparent; + owner = nullptr; + root_widget = agrparent->root_widget; + root = agrparent->root; + root_graph = agrparent->root_graph; + index = static_cast(agrparent->children.size()); + agrparent->children.push_back(this); + } + + predef_cursor = cursor::arrow; + flags.capture = false; + flags.dbl_click = true; + flags.enabled = true; + flags.modal = false; + flags.take_active = true; + flags.dropable = false; + flags.fullscreen = false; + flags.tab = nana::detail::tab_type::none; + flags.action = mouse_action::normal; + flags.refreshing = false; + flags.destroying = false; + flags.borderless = false; + + visible = false; + + color.foreground = 0x0; + color.background = nana::color::button_face; + color.active = 0x60C8FD; + + effect.edge_nimbus = effects::edge_nimbus::none; + effect.bground = nullptr; + effect.bground_fade_rate = 0; + + together.caret = nullptr; + together.attached_events = nullptr; + + extra_width = extra_height = 0; + + //The window must keep its thread_id same as its parent if it is a child. + //Otherwise, its root buffer would be mapped repeatly if it is in its parent thread. + thread_id = nana::system::this_thread_id(); + if(agrparent && (thread_id != agrparent->thread_id)) + thread_id = agrparent->thread_id; + } + + bool basic_window::set_events(const std::shared_ptr& p) + { + if (together.attached_events) + return false; + together.events_ptr = p; + together.attached_events = p.get(); + return true; + } + + general_events * basic_window::get_events() const + { + return together.attached_events; + } + //end struct basic_window + }//end namespace detail +}//end namespace nana diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp new file mode 100644 index 00000000..66dec171 --- /dev/null +++ b/source/gui/detail/bedrock_pi.cpp @@ -0,0 +1,331 @@ +/* +* A Bedrock Platform-Independent Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/bedrock_pi.cpp +*/ + +#include +#include PLATFORM_SPEC_HPP +#include GUI_BEDROCK_HPP +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nana +{ + namespace detail + { + void events_operation_register(event_handle evt) + { + bedrock::instance().evt_operation.register_evt(evt); + } + + void events_operation_cancel(event_handle evt) + { + bedrock::instance().evt_operation.cancel(evt); + } + + void bedrock::event_expose(core_window_t * wd, bool exposed) + { + if (nullptr == wd) return; + + wd->visible = exposed; + + arg_expose arg; + arg.exposed = exposed; + arg.window_handle = reinterpret_cast(wd); + if (emit(event_code::expose, wd, arg, false, get_thread_context())) + { + if (!exposed) + { + if (category::flags::root != wd->other.category) + { + //If the wd->parent is a lite_widget then find a parent until it is not a lite_widget + wd = wd->parent; + + while (category::flags::lite_widget == wd->other.category) + wd = wd->parent; + } + else if (category::flags::frame == wd->other.category) + wd = wd_manager.find_window(wd->root, wd->pos_root.x, wd->pos_root.y); + } + + wd_manager.refresh_tree(wd); + wd_manager.map(wd); + } + } + + void bedrock::event_move(core_window_t* wd, int x, int y) + { + if (wd) + { + arg_move arg; + arg.window_handle = reinterpret_cast(wd); + arg.x = x; + arg.y = y; + if (emit(event_code::move, wd, arg, false, get_thread_context())) + wd_manager.update(wd, true, true); + } + } + + bool bedrock::event_msleave(core_window_t* hovered) + { + if (wd_manager.available(hovered) && hovered->flags.enabled) + { + hovered->flags.action = mouse_action::normal; + + arg_mouse arg; + arg.evt_code = event_code::mouse_leave; + arg.window_handle = reinterpret_cast(hovered); + arg.pos.x = arg.pos.y = 0; + arg.left_button = arg.right_button = arg.mid_button = false; + arg.ctrl = arg.shift = false; + emit(event_code::mouse_leave, hovered, arg, true, get_thread_context()); + return true; + } + return false; + } + + void bedrock::update_cursor(core_window_t * wd) + { + internal_scope_guard isg; + if (wd_manager.available(wd)) + { + auto * thrd = get_thread_context(wd->thread_id); + if (nullptr == thrd) + return; + + auto pos = native_interface::cursor_position(); + auto native_handle = native_interface::find_window(pos.x, pos.y); + if (!native_handle) + return; + + native_interface::calc_window_point(native_handle, pos); + if (wd != wd_manager.find_window(native_handle, pos.x, pos.y)) + return; + + set_cursor(wd, wd->predef_cursor, thrd); + } + } + + void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::detail::event_arg_interface& event_arg) + { + switch (evt_code) + { + case event_code::click: + case event_code::dbl_click: + case event_code::mouse_enter: + case event_code::mouse_move: + case event_code::mouse_leave: + case event_code::mouse_down: + case event_code::mouse_up: + { + auto arg = dynamic_cast(&event_arg); + if (nullptr == arg) + return; + + void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&); + ::nana::basic_event* evt_addr; + switch (evt_code) + { + case event_code::click: + drawer_event_fn = &drawer::click; + evt_addr = &wd->together.attached_events->click; + break; + case event_code::dbl_click: + drawer_event_fn = &drawer::dbl_click; + evt_addr = &wd->together.attached_events->dbl_click; + break; + case event_code::mouse_enter: + drawer_event_fn = &drawer::mouse_enter; + evt_addr = &wd->together.attached_events->mouse_enter; + break; + case event_code::mouse_move: + drawer_event_fn = &drawer::mouse_move; + evt_addr = &wd->together.attached_events->mouse_move; + break; + case event_code::mouse_leave: + drawer_event_fn = &drawer::mouse_leave; + evt_addr = &wd->together.attached_events->mouse_leave; + break; + case event_code::mouse_down: + drawer_event_fn = &drawer::mouse_down; + evt_addr = &wd->together.attached_events->mouse_down; + break; + case event_code::mouse_up: + drawer_event_fn = &drawer::mouse_up; + evt_addr = &wd->together.attached_events->mouse_up; + break; + default: + throw std::runtime_error("Invalid mouse event code"); + } + + (wd->drawer.*drawer_event_fn)(*arg); + if (!draw_only) + evt_addr->emit(*arg); + + break; + } + case event_code::mouse_wheel: + { + auto arg = dynamic_cast(&event_arg); + if (arg) + { + wd->drawer.mouse_wheel(*arg); + if (!draw_only) + wd->together.attached_events->mouse_wheel.emit(*arg); + } + break; + } + case event_code::key_press: + case event_code::key_char: + case event_code::key_release: + case event_code::shortkey: + { + auto arg = dynamic_cast(&event_arg); + if (nullptr == arg) + return; + + void(::nana::detail::drawer::*drawer_event_fn)(const arg_keyboard&); + ::nana::basic_event* evt_addr; + + switch (evt_code) + { + case event_code::key_press: + drawer_event_fn = &drawer::key_press; + evt_addr = &wd->together.attached_events->key_press; + break; + case event_code::key_char: + drawer_event_fn = &drawer::key_char; + evt_addr = &wd->together.attached_events->key_char; + break; + case event_code::key_release: + drawer_event_fn = &drawer::key_release; + evt_addr = &wd->together.attached_events->key_release; + break; + case event_code::shortkey: + drawer_event_fn = &drawer::shortkey; + evt_addr = &wd->together.attached_events->shortkey; + break; + default: + throw std::runtime_error("Invalid keyboard event code"); + } + (wd->drawer.*drawer_event_fn)(*arg); + if (!draw_only) + evt_addr->emit(*arg); + break; + } + case event_code::expose: + if (!draw_only) + { + auto arg = dynamic_cast(&event_arg); + if (arg) + wd->together.attached_events->expose.emit(*arg); + } + break; + case event_code::focus: + { + auto arg = dynamic_cast(&event_arg); + if (arg) + { + wd->drawer.focus(*arg); + if (!draw_only) + wd->together.attached_events->focus.emit(*arg); + } + break; + } + case event_code::move: + { + auto arg = dynamic_cast(&event_arg); + if (arg) + { + wd->drawer.move(*arg); + if (!draw_only) + wd->together.attached_events->move.emit(*arg); + } + break; + } + case event_code::resizing: + { + auto arg = dynamic_cast(&event_arg); + if (arg) + { + wd->drawer.resizing(*arg); + if (!draw_only) + wd->together.attached_events->resizing.emit(*arg); + } + break; + } + case event_code::resized: + { + auto arg = dynamic_cast(&event_arg); + if (arg) + { + wd->drawer.resized(*arg); + if (!draw_only) + wd->together.attached_events->resized.emit(*arg); + } + break; + } + case event_code::unload: + if (!draw_only) + { + auto arg = dynamic_cast(&event_arg); + if (arg && (wd->other.category == category::flags::root)) + { + auto evt_ptr = dynamic_cast(wd->together.attached_events); + if (evt_ptr) + evt_ptr->unload.emit(*arg); + } + } + break; + case event_code::destroy: + if (!draw_only) + { + auto arg = dynamic_cast(&event_arg); + if (arg) + wd->together.attached_events->destroy.emit(*arg); + } + break; + default: + throw std::runtime_error("Invalid event code"); + } + } + + void bedrock::_m_except_handler() + { + std::vector v; + wd_manager.all_handles(v); + if (v.size()) + { + std::vector roots; + native_window_type root = nullptr; + unsigned tid = nana::system::this_thread_id(); + for (auto wd : v) + { + if ((wd->thread_id == tid) && (wd->root != root)) + { + root = wd->root; + if (roots.cend() == std::find(roots.cbegin(), roots.cend(), root)) + roots.push_back(root); + } + } + + for (auto i : roots) + interface_type::close_window(i); + } + } + }//end namespace detail +}//end namespace nana \ No newline at end of file diff --git a/source/gui/detail/bedrock_selector.cpp b/source/gui/detail/bedrock_selector.cpp new file mode 100644 index 00000000..62ca3673 --- /dev/null +++ b/source/gui/detail/bedrock_selector.cpp @@ -0,0 +1,23 @@ +/* + * Bedrock Selector + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Nana Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://nanapro.sourceforge.net/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/bedrock_selector.cpp + * + * This file is used to support the Nana project of some cross-platform IDE, + * + */ + +#include + +#if defined(NANA_WINDOWS) + #include "win32/bedrock.cpp" +#elif defined(NANA_LINUX) + #include "linux_X11/bedrock.cpp" +#endif + diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp new file mode 100644 index 00000000..42ef8cd8 --- /dev/null +++ b/source/gui/detail/drawer.cpp @@ -0,0 +1,388 @@ +/* + * A Drawer Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/drawer.cpp + */ + +#include +#include GUI_BEDROCK_HPP +#include +#include +#include +#include + +#if defined(NANA_X11) + #include +#endif + +#include + +namespace nana +{ + typedef detail::edge_nimbus_renderer edge_nimbus_renderer_t; + + //class drawer_trigger + drawer_trigger::~drawer_trigger(){} + void drawer_trigger::attached(widget_reference, graph_reference){} + void drawer_trigger::detached(){} //none-const + void drawer_trigger::typeface_changed(graph_reference){} + void drawer_trigger::refresh(graph_reference){} + + void drawer_trigger::resizing(graph_reference, const arg_resizing&) + { + overrided_ = false; + } + + void drawer_trigger::resized(graph_reference graph, const arg_resized&) + { + overrided_ = true; + this->refresh(graph); + detail::bedrock::instance().thread_context_lazy_refresh(); + } + + void drawer_trigger::move(graph_reference, const arg_move&) + { + overrided_ = false; + } + + void drawer_trigger::click(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::dbl_click(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_move(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_down(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_up(graph_reference, const arg_mouse&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&) + { + overrided_ = false; + } + + void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&) + { + overrided_ = false; + } + + void drawer_trigger::focus(graph_reference, const arg_focus&) + { + overrided_ = false; + } + + void drawer_trigger::key_press(graph_reference, const arg_keyboard&) + { + overrided_ = false; + } + + void drawer_trigger::key_char(graph_reference, const arg_keyboard&) + { + overrided_ = false; + } + + void drawer_trigger::key_release(graph_reference, const arg_keyboard&) + { + overrided_ = false; + } + + void drawer_trigger::shortkey(graph_reference, const arg_keyboard&) + { + overrided_ = false; + } + + void drawer_trigger::_m_reset_overrided() + { + overrided_ = true; + } + + bool drawer_trigger::_m_overrided() const + { + return overrided_; + } + + //end class drawer_trigger + + namespace detail + { + typedef bedrock bedrock_type; + + //class drawer + drawer::~drawer() + { + for(auto p : dynamic_drawing_objects_) + { + delete p; + } + } + + void drawer::bind(basic_window* cw) + { + core_window_ = cw; + } + + void drawer::typeface_changed() + { + if(realizer_) + realizer_->typeface_changed(graphics); + } + + void drawer::click(const arg_mouse& arg) + { + _m_emit(event_code::click, arg, &drawer_trigger::click); + } + + void drawer::dbl_click(const arg_mouse& arg) + { + _m_emit(event_code::dbl_click, arg, &drawer_trigger::dbl_click); + } + + void drawer::mouse_enter(const arg_mouse& arg) + { + _m_emit(event_code::mouse_enter, arg, &drawer_trigger::mouse_enter); + } + + void drawer::mouse_move(const arg_mouse& arg) + { + _m_emit(event_code::mouse_move, arg, &drawer_trigger::mouse_move); + } + + void drawer::mouse_leave(const arg_mouse& arg) + { + _m_emit(event_code::mouse_leave, arg, &drawer_trigger::mouse_leave); + } + + void drawer::mouse_down(const arg_mouse& arg) + { + _m_emit(event_code::mouse_down, arg, &drawer_trigger::mouse_down); + } + + void drawer::mouse_up(const arg_mouse& arg) + { + _m_emit(event_code::mouse_up, arg, &drawer_trigger::mouse_up); + } + + void drawer::mouse_wheel(const arg_wheel& arg) + { + _m_emit(event_code::mouse_wheel, arg, &drawer_trigger::mouse_wheel); + } + + void drawer::mouse_dropfiles(const arg_dropfiles& arg) + { + _m_emit(event_code::mouse_drop, arg, &drawer_trigger::mouse_dropfiles); + } + + void drawer::resizing(const arg_resizing& arg) + { + _m_emit(event_code::resizing, arg, &drawer_trigger::resizing); + } + + void drawer::resized(const arg_resized& arg) + { + _m_emit(event_code::resized, arg, &drawer_trigger::resized); + } + + void drawer::move(const arg_move& arg) + { + _m_emit(event_code::move, arg, &drawer_trigger::move); + } + + void drawer::focus(const arg_focus& arg) + { + _m_emit(event_code::focus, arg, &drawer_trigger::focus); + } + + void drawer::key_press(const arg_keyboard& arg) + { + _m_emit(event_code::key_press, arg, &drawer_trigger::key_press); + } + + void drawer::key_char(const arg_keyboard& arg) + { + _m_emit(event_code::key_char, arg, &drawer_trigger::key_char); + } + + void drawer::key_release(const arg_keyboard& arg) + { + _m_emit(event_code::key_release, arg, &drawer_trigger::key_release); + } + + void drawer::shortkey(const arg_keyboard& arg) + { + _m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey); + } + + void drawer::map(window wd) //Copy the root buffer to screen + { + if(wd) + { + bedrock_type::core_window_t* iwd = reinterpret_cast(wd); + bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus; + + bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible())); + + //The caret in X11 is implemented by Nana, it is different from Windows' + //the caret in X11 is asynchronous, it is hard to hide and show the caret + //immediately, and therefore the caret always be flickering when the graphics + //buffer is mapping to the window. + if(owns_caret) + { +#ifndef NANA_X11 + caret_wd->together.caret->visible(false); +#else + owns_caret = nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, false); +#endif + } + + if(false == edge_nimbus_renderer_t::instance().render(iwd)) + { + nana::rectangle vr; + if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y); + } + + if(owns_caret) + { +#ifndef NANA_X11 + caret_wd->together.caret->visible(true); +#else + nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, true); +#endif + } + } + } + + void drawer::refresh() + { + if(realizer_ && (refreshing_ == false)) + { + refreshing_ = true; + _m_bground_pre(); + realizer_->refresh(graphics); + _m_draw_dynamic_drawing_object(); + _m_bground_end(); + graphics.flush(); + refreshing_ = false; + } + } + + drawer_trigger* drawer::realizer() const + { + return realizer_; + } + + void drawer::attached(widget& wd, drawer_trigger& realizer) + { + for (auto i = std::begin(mth_state_), end = std::end(mth_state_); i != end; ++i) + *i = method_state::unknown; + + realizer_ = &realizer; + realizer.attached(wd, graphics); + } + + drawer_trigger* drawer::detached() + { + if(realizer_) + { + auto rmp = realizer_; + realizer_ = nullptr; + rmp->detached(); + return rmp; + } + return nullptr; + } + + void drawer::clear() + { + std::vector then; + for(auto p : dynamic_drawing_objects_) + { + if(p->diehard()) + then.push_back(p); + else + delete p; + } + + then.swap(dynamic_drawing_objects_); + } + + void* drawer::draw(std::function && f, bool diehard) + { + if(f) + { + auto p = new dynamic_drawing::user_draw_function(std::move(f), diehard); + dynamic_drawing_objects_.push_back(p); + return (diehard ? p : nullptr); + } + return nullptr; + } + + void drawer::erase(void * p) + { + if(p) + { + auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p); + if (i != dynamic_drawing_objects_.end()) + { + delete (*i); + dynamic_drawing_objects_.erase(i); + } + } + } + + void drawer::_m_bground_pre() + { + if(core_window_->effect.bground && core_window_->effect.bground_fade_rate < 0.01) + core_window_->other.glass_buffer.paste(graphics, 0, 0); + } + + void drawer::_m_bground_end() + { + if(core_window_->effect.bground && core_window_->effect.bground_fade_rate >= 0.01) + core_window_->other.glass_buffer.blend(core_window_->other.glass_buffer.size(), graphics, nana::point(), core_window_->effect.bground_fade_rate); + } + + void drawer::_m_draw_dynamic_drawing_object() + { + for(auto * dw : dynamic_drawing_objects_) + dw->draw(graphics); + } + + //If the drawer_trigger didn't declear a lazy refresh, then use the refresh(). + void drawer::_m_use_refresh() + { + if (basic_window::update_state::refresh != core_window_->other.upd_state) + refresh(); + } + }//end namespace detail +}//end namespace nana diff --git a/source/gui/detail/element_store.cpp b/source/gui/detail/element_store.cpp new file mode 100644 index 00000000..39608754 --- /dev/null +++ b/source/gui/detail/element_store.cpp @@ -0,0 +1,45 @@ +/* +* The Store for the Storage Of Elements +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/element_store.cpp +*/ +#include + +namespace nana +{ +namespace detail +{ + //class element_store + element_store::data::data() + : fast_ptr(nullptr) + {} + + nana::element::element_interface * const * element_store::bground(const std::string& name) + { + element_interface * const * addr = &(bground_.table[name].fast_ptr); + return addr; + } + + void element_store::bground(const std::string& name, const pat::cloneable& rhs) + { + auto & store = bground_.table[name]; + + store.object = rhs; + store.fast_ptr = store.object.get(); + } + + void element_store::bground(const std::string& name, pat::cloneable&& rv) + { + auto & store = bground_.table[name]; + + store.object = std::move(rv); + store.fast_ptr = store.object.get(); + } +}//end namespace detail +} diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp new file mode 100644 index 00000000..ea11923b --- /dev/null +++ b/source/gui/detail/events_operation.cpp @@ -0,0 +1,52 @@ +#include + +namespace nana +{ + namespace detail + { + //class events_operation + typedef std::lock_guard lock_guard; + + void events_operation::make(window wd, const std::shared_ptr& sp) + { + lock_guard lock(mutex_); + evt_table_[wd] = sp; + } + + void events_operation::umake(window wd) + { + lock_guard lock(mutex_); + evt_table_.erase(wd); + } + + void events_operation::register_evt(event_handle evt) + { + lock_guard lock(mutex_); + register_.insert(evt); + } + + void events_operation::cancel(event_handle evt) + { + lock_guard lock(mutex_); + register_.erase(evt); + } + + void events_operation::erase(event_handle evt) + { + lock_guard lock(mutex_); + + auto i = register_.find(evt); + if (i != register_.end()) + { + reinterpret_cast(evt)->get_event()->remove(evt); + } + } + + std::size_t events_operation::size() const + { + lock_guard lock(mutex_); + return register_.size(); + } + //end namespace events_operation + }//end namespace detail +}//end namespace nana \ No newline at end of file diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp new file mode 100644 index 00000000..2a82d049 --- /dev/null +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -0,0 +1,1295 @@ +/* + * A Bedrock Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://nanapro.sourceforge.net/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/linux_X11/bedrock.cpp + */ + +#include +#include PLATFORM_SPEC_HPP +#include GUI_BEDROCK_HPP +#include +#include +#include +#include +#include +#include +#include + +namespace nana +{ + //class internal_scope_guard + internal_scope_guard::internal_scope_guard() + { + detail::bedrock::instance().wd_manager.internal_lock().lock(); + } + internal_scope_guard::~internal_scope_guard() + { + detail::bedrock::instance().wd_manager.internal_lock().unlock(); + } + //end class internal_scope_guard +namespace detail +{ +#pragma pack(1) + union event_mask + { + struct + { + short x; + short y; + }pos; + + struct + { + short width; + short height; + }size; + + struct + { + unsigned short vkey; + short delta; + }wheel; + }; +#pragma pack() + + struct bedrock::thread_context + { + unsigned event_pump_ref_count{0}; + + int window_count{0}; //The number of windows + core_window_t* event_window{nullptr}; + bool is_alt_pressed{false}; + + struct platform_detail_tag + { + nana::char_t keychar; + native_window_type motion_window; + nana::point motion_pointer_pos; + }platform; + + struct cursor_tag + { + core_window_t * window; + native_window_type native_handle; + nana::cursor predef_cursor; + Cursor handle; + }cursor; + + thread_context() + { + cursor.window = nullptr; + cursor.native_handle = nullptr; + cursor.predef_cursor = nana::cursor::arrow; + cursor.handle = 0; + } + }; + + struct bedrock::private_impl + { + typedef std::map thr_context_container; + std::recursive_mutex mutex; + thr_context_container thr_contexts; + + element_store estore; + + struct cache_type + { + struct thread_context_cache + { + unsigned tid; + thread_context *object; + }tcontext; + + cache_type() + { + tcontext.tid = 0; + tcontext.object = nullptr; + } + }cache; + + struct menu_tag + { + menu_tag() + :taken_window(nullptr), window(nullptr), owner(nullptr), has_keyboard(false) + {} + + core_window_t* taken_window; + native_window_type window; + native_window_type owner; + bool has_keyboard; + }menu; + + struct keyboard_tracking_state_tag + { + keyboard_tracking_state_tag() + :has_shortkey_occured(false), has_keyup(true), alt(0) + {} + + bool has_shortkey_occured; + bool has_keyup; + + unsigned long alt : 2; + }keyboard_tracking_state; + }; + + void timer_proc(unsigned); + void window_proc_dispatcher(Display*, nana::detail::msg_packet_tag&); + void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&); + void window_proc_for_xevent(Display*, XEvent&); + + //class bedrock defines a static object itself to implement a static singleton + //here is the definition of this object + bedrock bedrock::bedrock_object; + + inline window mycast(bedrock::core_window_t* wd) + { + return reinterpret_cast(wd); + } + + Window event_window(const XEvent& event) + { + switch(event.type) + { + case MapNotify: + case UnmapNotify: + case DestroyNotify: + return event.xmap.window; + } + return event.xkey.window; + } + + bedrock::bedrock() + : impl_(new private_impl) + { + nana::detail::platform_spec::instance().msg_set(timer_proc, window_proc_dispatcher); + } + + bedrock::~bedrock() + { + delete impl_; + } + + void bedrock::map_thread_root_buffer(bedrock::core_window_t* wnd) + { + //GUI in X11 is not thread-dependent, so no implementation. + } + + //inc_window + //@biref: increament the number of windows + int bedrock::inc_window(unsigned tid) + { + private_impl * impl = instance().impl_; + std::lock_guardmutex)> lock(impl->mutex); + + int & cnt = (impl->thr_contexts[tid ? tid : nana::system::this_thread_id()].window_count); + return (cnt < 0 ? cnt = 1 : ++cnt); + } + + bedrock::thread_context* bedrock::open_thread_context(unsigned tid) + { + if(0 == tid) tid = nana::system::this_thread_id(); + + std::lock_guardmutex)> lock(impl_->mutex); + if(impl_->cache.tcontext.tid == tid) + return impl_->cache.tcontext.object; + + bedrock::thread_context* context = nullptr; + + private_impl::thr_context_container::iterator i = impl_->thr_contexts.find(tid); + if(i == impl_->thr_contexts.end()) + context = &(impl_->thr_contexts[tid]); + else + context = &(i->second); + + impl_->cache.tcontext.tid = tid; + impl_->cache.tcontext.object = context; + return context; + } + + bedrock::thread_context* bedrock::get_thread_context(unsigned tid) + { + if(0 == tid) tid = nana::system::this_thread_id(); + + std::lock_guardmutex)> lock(impl_->mutex); + if(impl_->cache.tcontext.tid == tid) + return impl_->cache.tcontext.object; + + private_impl::thr_context_container::iterator i = impl_->thr_contexts.find(tid); + if(i != impl_->thr_contexts.end()) + { + impl_->cache.tcontext.tid = tid; + return (impl_->cache.tcontext.object = &(i->second)); + } + + impl_->cache.tcontext.tid = 0; + return 0; + } + + void bedrock::remove_thread_context(unsigned tid) + { + if(0 == tid) tid = nana::system::this_thread_id(); + + std::lock_guardmutex)> lock(impl_->mutex); + + if(impl_->cache.tcontext.tid == tid) + { + impl_->cache.tcontext.tid = 0; + impl_->cache.tcontext.object = nullptr; + } + + impl_->thr_contexts.erase(tid); + } + + bedrock& bedrock::instance() + { + return bedrock_object; + } + + category::flags bedrock::category(bedrock::core_window_t* wd) + { + if(wd) + { + internal_scope_guard isg; + if(wd_manager.available(wd)) + return wd->other.category; + } + return category::flags::super; + } + + bedrock::core_window_t* bedrock::focus() + { + core_window_t* wd = wd_manager.root(native_interface::get_focus_window()); + return (wd ? wd->other.attribute.root->focus : 0); + } + + native_window_type bedrock::root(core_window_t* wd) + { + if(wd) + { + internal_scope_guard isg; + if(wd_manager.available(wd)) + return wd->root; + } + return nullptr; + } + + void bedrock::set_menubar_taken(core_window_t* wd) + { + impl_->menu.taken_window = wd; + } + + bedrock::core_window_t* bedrock::get_menubar_taken() + { + core_window_t* wd = impl_->menu.taken_window; + impl_->menu.taken_window = nullptr; + return wd; + } + + bool bedrock::close_menu_if_focus_other_window(native_window_type wd) + { + if(impl_->menu.window && (impl_->menu.window != wd)) + { + wd = native_interface::get_owner_window(wd); + while(wd) + { + if(wd != impl_->menu.window) + wd = native_interface::get_owner_window(wd); + else + return false; + } + remove_menu(); + return true; + } + return false; + } + + void bedrock::set_menu(native_window_type menu_window, bool has_keyboard) + { + if(menu_window && impl_->menu.window != menu_window) + { + remove_menu(); + impl_->menu.window = menu_window; + impl_->menu.owner = native_interface::get_owner_window(menu_window); + impl_->menu.has_keyboard = has_keyboard; + } + } + + native_window_type bedrock::get_menu(native_window_type owner, bool is_keyboard_condition) + { + if( (impl_->menu.owner == nullptr) || + (owner && (impl_->menu.owner == owner)) + ) + { + return ( is_keyboard_condition ? (impl_->menu.has_keyboard ? impl_->menu.window : nullptr) : impl_->menu.window); + } + + return 0; + } + + native_window_type bedrock::get_menu() + { + return impl_->menu.window; + } + + void bedrock::remove_menu() + { + if(impl_->menu.window) + { + native_window_type delwin = impl_->menu.window; + impl_->menu.window = impl_->menu.owner = nullptr; + impl_->menu.has_keyboard = false; + native_interface::close_window(delwin); + } + } + + void bedrock::empty_menu() + { + if(impl_->menu.window) + { + impl_->menu.window = impl_->menu.owner = nullptr; + impl_->menu.has_keyboard = false; + } + } + + void bedrock::get_key_state(arg_keyboard& arg) + { + XKeyEvent xkey; + nana::detail::platform_spec::instance().read_keystate(xkey); + arg.ctrl = (xkey.state & ControlMask); + } + + bool bedrock::set_keyboard_shortkey(bool yes) + { + bool ret = impl_->keyboard_tracking_state.has_shortkey_occured; + impl_->keyboard_tracking_state.has_shortkey_occured = yes; + return ret; + } + + element_store& bedrock::get_element_store() const + { + return impl_->estore; + } + + bool bedrock::emit(event_code evt_code, core_window_t* wd, const arg_mouse& arg, bool ask_update, thread_context* thrd) + { + if(evt_code != arg.evt_code) + throw std::runtime_error("Nana.bedrock: Invalid event arg."); + return emit(evt_code, wd, static_cast(arg), ask_update, thrd); + } + + bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, bool ask_update, thread_context* thrd) + { + if(wd_manager.available(wd) == false) + return false; + + core_window_t * prev_wd; + if(thrd) + { + prev_wd = thrd->event_window; + thrd->event_window = wd; + _m_event_filter(evt_code, wd, thrd); + } + + if(wd->other.upd_state == core_window_t::update_state::none) + wd->other.upd_state = core_window_t::update_state::lazy; + + _m_emit_core(evt_code, wd, false, arg); + + if(ask_update) + wd_manager.do_lazy_refresh(wd, false); + else + wd->other.upd_state = core_window_t::update_state::none; + + if(thrd) thrd->event_window = prev_wd; + return true; + } + + bool bedrock::emit_drawer(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, thread_context* thrd) + { + if(wd_manager.available(wd) == false) + return false; + + core_window_t * prev_wd; + if(thrd) + { + prev_wd = thrd->event_window; + thrd->event_window = wd; + _m_event_filter(evt_code, wd, thrd); + } + + if(wd->other.upd_state == core_window_t::update_state::none) + wd->other.upd_state = core_window_t::update_state::lazy; + + _m_emit_core(evt_code, wd, true, arg); + + if(thrd) thrd->event_window = prev_wd; + return true; + + } + + void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt) + { + arg.window_handle = reinterpret_cast(wd); + if (ButtonPress == msg || ButtonRelease == msg) + { + if (evt.xbutton.button != Button4 && evt.xbutton.button != Button5) + { + arg.evt_code = (ButtonPress == msg ? event_code::mouse_down : event_code::mouse_up); + arg.pos.x = evt.xbutton.x - wd->pos_root.x; + arg.pos.y = evt.xbutton.y - wd->pos_root.y; + + arg.left_button = arg.mid_button = arg.right_button = false; + arg.shift = arg.ctrl = false; + switch (evt.xbutton.button) + { + case Button1: + arg.left_button = true; + break; + case Button2: + arg.mid_button = true; + break; + case Button3: + arg.right_button = true; + break; + } + } + } + else if (msg == MotionNotify) + { + arg.evt_code = event_code::mouse_move; + arg.pos.x = evt.xmotion.x - wd->pos_root.x; + arg.pos.y = evt.xmotion.y - wd->pos_root.y; + arg.left_button = arg.mid_button = arg.right_button = false; + + arg.shift = evt.xmotion.state & ShiftMask; + arg.ctrl = evt.xmotion.state & ControlMask; + if (evt.xmotion.state & Button1Mask) + arg.left_button = true; + else if (evt.xmotion.state & Button2Mask) + arg.right_button = true; + else if (evt.xmotion.state & Button3Mask) + arg.mid_button = true; + } + else if (EnterNotify == msg) + { + arg.evt_code = event_code::mouse_enter; + arg.pos.x = evt.xcrossing.x - wd->pos_root.x; + arg.pos.y = evt.xcrossing.y - wd->pos_root.y; + arg.left_button = arg.mid_button = arg.right_button = false; + + arg.shift = evt.xcrossing.state & ShiftMask; + arg.ctrl = evt.xcrossing.state & ControlMask; + if (evt.xcrossing.state & Button1Mask) + arg.left_button = true; + else if (evt.xcrossing.state & Button2Mask) + arg.right_button = true; + else if (evt.xcrossing.state & Button3Mask) + arg.mid_button = true; + } + } + + void assign_arg(arg_focus& arg, basic_window* wd, native_window_type recv, bool getting) + { + arg.window_handle = reinterpret_cast(wd); + arg.receiver = recv; + arg.getting = getting; + } + + void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt) + { + arg.evt_code = event_code::mouse_wheel; + arg.window_handle = reinterpret_cast(wd); + if (ButtonRelease == evt.type && (evt.xbutton.button == Button4 || evt.xbutton.button == Button5)) + { + arg.evt_code = event_code::mouse_wheel; + arg.pos.x = evt.xbutton.x - wd->pos_root.x; + arg.pos.y = evt.xbutton.y - wd->pos_root.y; + + arg.upwards = (evt.xbutton.button == Button4); + arg.left_button = arg.mid_button = arg.right_button = false; + arg.shift = arg.ctrl = false; + arg.distance = 120; + arg.which = arg_wheel::wheel::vertical; + } + + } + + void timer_proc(unsigned tid) + { + nana::detail::platform_spec::instance().timer_proc(tid); + } + + void window_proc_dispatcher(Display* display, nana::detail::msg_packet_tag& msg) + { + switch(msg.kind) + { + case nana::detail::msg_packet_tag::kind_xevent: + window_proc_for_xevent(display, msg.u.xevent); + break; + case nana::detail::msg_packet_tag::kind_mouse_drop: + window_proc_for_packet(display, msg); + break; + default: break; + } + } + + void window_proc_for_packet(Display * display, nana::detail::msg_packet_tag& msg) + { + static auto& brock = detail::bedrock::instance(); + + auto native_window = reinterpret_cast(msg.u.packet_window); + auto root_runtime = brock.wd_manager.root_runtime(native_window); + + if(root_runtime) + { + auto msgwd = root_runtime->window; + + switch(msg.kind) + { + case nana::detail::msg_packet_tag::kind_mouse_drop: + msgwd = brock.wd_manager.find_window(native_window, msg.u.mouse_drop.x, msg.u.mouse_drop.y); + if(msgwd) + { + arg_dropfiles arg; + arg.window_handle = reinterpret_cast(msgwd); + arg.files.swap(*msg.u.mouse_drop.files); + delete msg.u.mouse_drop.files; + arg.pos.x = msg.u.mouse_drop.x - msgwd->pos_root.x; + arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y; + msgwd->together.attached_events->mouse_dropfiles.emit(arg); + brock.wd_manager.do_lazy_refresh(msgwd, false); + } + break; + default: + throw std::runtime_error("Nana.GUI.Bedrock: Undefined message packet"); + } + } + } + + template + void emit_drawer(void(::nana::detail::drawer::*event_ptr)(const Arg&), basic_window* wd, const Arg& arg, bedrock::thread_context* thrd) + { + if(bedrock::instance().wd_manager.available(wd) == false) + return; + basic_window * pre_wd; + if(thrd) + { + pre_wd = thrd->event_window; + thrd->event_window = wd; + } + + if(wd->other.upd_state == basic_window::update_state::none) + wd->other.upd_state = basic_window::update_state::lazy; + + (wd->drawer.*event_ptr)(arg); + if(thrd) thrd->event_window = pre_wd; + } + + void window_proc_for_xevent(Display* display, XEvent& xevent) + { + typedef detail::bedrock::core_window_t core_window_t; + + static auto& brock = detail::bedrock::instance(); + static unsigned long last_mouse_down_time; + static core_window_t* last_mouse_down_window; + + auto native_window = reinterpret_cast(event_window(xevent)); + auto root_runtime = brock.wd_manager.root_runtime(native_window); + + if(root_runtime) + { + auto msgwnd = root_runtime->window; + auto& context = *brock.get_thread_context(msgwnd->thread_id); + + auto pre_event_window = context.event_window; + auto pressed_wd = root_runtime->condition.pressed; + auto hovered_wd = root_runtime->condition.hovered; + + const int message = xevent.type; + switch(xevent.type) + { + case EnterNotify: + msgwnd = brock.wd_manager.find_window(native_window, xevent.xcrossing.x, xevent.xcrossing.y); + if(msgwnd) + { + msgwnd->flags.action = mouse_action::over; + hovered_wd = msgwnd; + + arg_mouse arg; + assign_arg(arg, msgwnd, message, xevent); + brock.emit(event_code::mouse_enter, msgwnd, arg, true, &context); + + arg.evt_code = event_code::mouse_move; + brock.emit(event_code::mouse_move, msgwnd, arg, true, &context); + + if (!brock.wd_manager.available(hovered_wd)) + hovered_wd = nullptr; + } + break; + case LeaveNotify: + brock.event_msleave(hovered_wd); + hovered_wd = nullptr; + break; + case FocusIn: + if(msgwnd->flags.enabled && msgwnd->flags.take_active) + { + auto focus = msgwnd->other.attribute.root->focus; + if(focus && focus->together.caret) + focus->together.caret->set_active(true); + msgwnd->root_widget->other.attribute.root->context.focus_changed = true; + + arg_focus arg; + arg.window_handle = reinterpret_cast(focus); + arg.receiver = native_window; + arg.getting = true; + if(!brock.emit(event_code::focus, focus, arg, true, &context)) + brock.wd_manager.set_focus(msgwnd, true); + } + break; + case FocusOut: + if(msgwnd->other.attribute.root->focus && native_interface::is_window(msgwnd->root)) + { + nana::point pos = native_interface::cursor_position(); + auto recv = native_interface::find_window(pos.x, pos.y); + + auto focus = msgwnd->other.attribute.root->focus; + arg_focus arg; + arg.window_handle = reinterpret_cast(focus); + arg.getting = false; + arg.receiver = recv; + if(brock.emit(event_code::focus, focus, arg, true, &context)) + { + if(focus->together.caret) + focus->together.caret->set_active(false); + } + brock.close_menu_if_focus_other_window(recv); + } + break; + case ConfigureNotify: + if(msgwnd->dimension.width != static_cast(xevent.xconfigure.width) || msgwnd->dimension.height != static_cast(xevent.xconfigure.height)) + { + auto & cf = xevent.xconfigure; + brock.wd_manager.size(msgwnd, nana::size{static_cast(cf.width), static_cast(cf.height)}, true, true); + } + + if(msgwnd->pos_native.x != xevent.xconfigure.x || msgwnd->pos_native.y != xevent.xconfigure.y) + { + msgwnd->pos_native.x = xevent.xconfigure.x; + msgwnd->pos_native.y = xevent.xconfigure.y; + brock.event_move(msgwnd, xevent.xconfigure.x, xevent.xconfigure.y); + } + break; + case ButtonPress: + if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5) + break; + + msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); + if(nullptr == msgwnd) break; + + if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) + brock.remove_menu(); + else + brock.close_menu_if_focus_other_window(msgwnd->root); + + if(msgwnd->flags.enabled) + { + bool dbl_click = (last_mouse_down_window == msgwnd) && (xevent.xbutton.time - last_mouse_down_time <= 400); + last_mouse_down_time = xevent.xbutton.time; + last_mouse_down_window = msgwnd; + auto new_focus = (msgwnd->flags.take_active ? msgwnd : msgwnd->other.active_window); + + if(new_focus) + { + context.event_window = new_focus; + auto kill_focus = brock.wd_manager.set_focus(new_focus, false); + if(kill_focus != new_focus) + brock.wd_manager.do_lazy_refresh(kill_focus, false); + } + msgwnd->root_widget->other.attribute.root->context.focus_changed = false; + + context.event_window = msgwnd; + + pressed_wd = nullptr; + //make_eventinfo(ei, msgwnd, message, xevent); + msgwnd->flags.action = mouse_action::pressed; + arg_mouse arg; + assign_arg(arg, msgwnd, ButtonPress, xevent); + arg.evt_code = dbl_click ? event_code::dbl_click : event_code::mouse_down; + if(brock.emit(arg.evt_code, msgwnd, arg, true, &context)) + { + if (brock.wd_manager.available(msgwnd)) + { + pressed_wd = msgwnd; + //If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. + if(msgwnd->root_widget->other.attribute.root->context.focus_changed) + { + //call the drawer mouse up event for restoring the surface graphics + msgwnd->flags.action = mouse_action::normal; + emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); + brock.wd_manager.do_lazy_refresh(msgwnd, false); + } + } + } + } + break; + case ButtonRelease: + if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5) + { + //The hovered window receives the message, unlike in Windows, no redirection is required. + nana::point mspos{xevent.xbutton.x, xevent.xbutton.y}; + while(msgwnd) + { + if(msgwnd->together.attached_events->mouse_wheel.length() != 0) + { + mspos -= msgwnd->pos_root; + arg_wheel arg; + arg.which = arg_wheel::wheel::vertical; + assign_arg(arg, msgwnd, xevent); + brock.emit(event_code::mouse_wheel, msgwnd, arg, true, &context); + break; + } + msgwnd = msgwnd->parent; + } + } + else + { + msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); + if(nullptr == msgwnd) + break; + + msgwnd->flags.action = mouse_action::normal; + if(msgwnd->flags.enabled) + { + arg_mouse arg; + assign_arg(arg, msgwnd, message, xevent); + + const bool hit = msgwnd->dimension.is_hit(arg.pos); + bool fire_click = false; + if(msgwnd == pressed_wd) + { + if(msgwnd->flags.enabled && hit) + { + msgwnd->flags.action = mouse_action::over; + arg.evt_code = event_code::click; + emit_drawer(&drawer::click, msgwnd, arg, &context); + fire_click = true; + } + } + + //Do mouse_up, this handle may be closed by click handler. + if(brock.wd_manager.available(msgwnd) && msgwnd->flags.enabled) + { + if(hit) + msgwnd->flags.action = mouse_action::over; + + auto events_ptr = msgwnd->together.events_ptr; + arg.evt_code = event_code::mouse_up; + emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); + + if(fire_click) + { + arg.evt_code = event_code::click; + msgwnd->together.attached_events->click.emit(arg); + } + + if (brock.wd_manager.available(msgwnd)) + { + arg.evt_code = event_code::mouse_up; + msgwnd->together.attached_events->mouse_up.emit(arg); + } + } + else if(fire_click) + { + arg.evt_code = event_code::click; + msgwnd->together.attached_events->click.emit(arg); + } + brock.wd_manager.do_lazy_refresh(msgwnd, false); + } + pressed_wd = nullptr; + } + break; + case DestroyNotify: + { + auto & spec = nana::detail::platform_spec::instance(); + if(brock.wd_manager.available(msgwnd)) + { + //The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window(). + if(msgwnd->root == brock.get_menu()) + brock.empty_menu(); + + spec.remove(native_window); + brock.wd_manager.destroy(msgwnd); + + brock.rt_manager.remove_if_exists(msgwnd); + brock.wd_manager.destroy_handle(msgwnd); + } + } + break; + case MotionNotify: + //X may send the MotionNotify with same information repeatly. + //Nana should ignore the repeated notify. + if(context.platform.motion_window != native_window || context.platform.motion_pointer_pos != nana::point(xevent.xmotion.x, xevent.xmotion.y)) + { + context.platform.motion_window = native_window; + context.platform.motion_pointer_pos = nana::point(xevent.xmotion.x, xevent.xmotion.y); + } + else + break; + + msgwnd = brock.wd_manager.find_window(native_window, xevent.xmotion.x, xevent.xmotion.y); + if (brock.wd_manager.available(hovered_wd) && (msgwnd != hovered_wd)) + { + brock.event_msleave(hovered_wd); + hovered_wd->flags.action = mouse_action::normal; + hovered_wd = nullptr; + + //if msgwnd is neither a captured window nor a child of captured window, + //redirect the msgwnd to the captured window. + auto cap_wd = brock.wd_manager.capture_redirect(msgwnd); + if(cap_wd) + msgwnd = cap_wd; + } + else if(msgwnd) + { + bool prev_captured_inside; + if(brock.wd_manager.capture_window_entered(xevent.xmotion.x, xevent.xmotion.y, prev_captured_inside)) + { + event_code evt_code; + if(prev_captured_inside) + { + evt_code = event_code::mouse_leave; + msgwnd->flags.action = mouse_action::normal; + } + else + { + evt_code = event_code::mouse_enter; + msgwnd->flags.action = mouse_action::over; + } + arg_mouse arg; + assign_arg(arg, msgwnd, message, xevent); + arg.evt_code = evt_code; + brock.emit(evt_code, msgwnd, arg, true, &context); + } + } + + if(msgwnd) + { + arg_mouse arg; + assign_arg(arg, msgwnd, message, xevent); + msgwnd->flags.action = mouse_action::over; + if (hovered_wd != msgwnd) + { + hovered_wd = msgwnd; + arg.evt_code = event_code::mouse_enter; + brock.emit(event_code::mouse_enter, msgwnd, arg, true, &context); + } + + arg.evt_code = event_code::mouse_move; + brock.emit(event_code::mouse_move, msgwnd, arg, true, &context); + } + if (!brock.wd_manager.available(hovered_wd)) + hovered_wd = nullptr; + break; + case MapNotify: + case UnmapNotify: + brock.event_expose(msgwnd, (xevent.type == MapNotify)); + context.platform.motion_window = nullptr; + break; + case Expose: + if(msgwnd->visible && (msgwnd->root_graph->empty() == false)) + { + nana::detail::platform_scope_guard psg; + nana::detail::drawable_impl_type* drawer_impl = msgwnd->root_graph->handle(); + ::XCopyArea(display, drawer_impl->pixmap, reinterpret_cast(native_window), drawer_impl->context, + xevent.xexpose.x, xevent.xexpose.y, + xevent.xexpose.width, xevent.xexpose.height, + xevent.xexpose.x, xevent.xexpose.y); + } + break; + case KeyPress: + nana::detail::platform_spec::instance().write_keystate(xevent.xkey); + if(msgwnd->flags.enabled) + { + if(msgwnd->root != brock.get_menu()) + msgwnd = brock.focus(); + + if(msgwnd) + { + KeySym keysym; + Status status; + char fixbuf[33]; + char * keybuf = fixbuf; + int len = 0; + XIC input_context = nana::detail::platform_spec::instance().caret_input_context(native_window); + if(input_context) + { + nana::detail::platform_scope_guard psg; +#if defined(NANA_UNICODE) + len = ::Xutf8LookupString(input_context, &xevent.xkey, keybuf, 32, &keysym, &status); + if(status == XBufferOverflow) + { + keybuf = new char[len + 1]; + len = ::Xutf8LookupString(input_context, &xevent.xkey, keybuf, len, &keysym, &status); + } +#else + len = ::XmbLookupString(input_context, &xevent.xkey, keybuf, 32, &keysym, &status); + if(status == XBufferOverflow) + { + keybuf = new char[len + 1]; + len = ::XmbLookupString(input_context, &xevent.xkey, keybuf, len, &keysym, &status); + } +#endif + } + else + { + nana::detail::platform_scope_guard psg; + status = XLookupBoth; + len = ::XLookupString(&xevent.xkey, keybuf, 32, &keysym, 0); + } + + keybuf[len] = 0; + nana::char_t keychar; + switch(status) + { + case XLookupKeySym: + case XLookupBoth: + switch(keysym) + { + case XK_Alt_L: case XK_Alt_R: + keychar = keyboard::alt; break; + case XK_BackSpace: + keychar = keyboard::backspace; break; + case XK_Tab: + keychar = keyboard::tab; break; + case XK_Escape: + keychar = keyboard::escape; break; + case XK_Return: + keychar = keyboard::enter; break; + case XK_Cancel: + keychar = keyboard::end_of_text;break; //Ctrl+C + case XK_Page_Up: + keychar = keyboard::os_pageup; break; + case XK_Page_Down: + keychar = keyboard::os_pagedown; break; + case XK_Left: case XK_Up: case XK_Right: case XK_Down: + keychar = keyboard::os_arrow_left + (keysym - XK_Left); break; + case XK_Insert: + keychar = keyboard::os_insert; break; + case XK_Delete: + keychar = keyboard::os_del; break; + default: + keychar = keysym; + } + context.platform.keychar = keychar; + if(keychar == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab + { + auto the_next = brock.wd_manager.tabstop(msgwnd, true); + if(the_next) + { + brock.wd_manager.set_focus(the_next, false); + brock.wd_manager.do_lazy_refresh(the_next, true); + root_runtime->condition.tabstop_focus_changed = true; + } + } + else if(keyboard::alt == keychar) + { + context.is_alt_pressed = true; + } + else + { + arg_keyboard arg; + arg.ignore = false; + arg.key = keychar; + arg.evt_code = event_code::key_press; + brock.get_key_state(arg); + arg.window_handle = reinterpret_cast(msgwnd); + brock.emit(event_code::key_press, msgwnd, arg, true, &context); + } + + if(XLookupKeySym == status) + { + brock.wd_manager.do_lazy_refresh(msgwnd, false); + break; + } + case XLookupChars: + { + const nana::char_t * charbuf; +#if defined(NANA_UNICODE) + nana::detail::charset_conv charset("UTF-32", "UTF-8"); + const std::string& str = charset.charset(std::string(keybuf, keybuf + len)); + charbuf = reinterpret_cast(str.c_str()) + 1; + len = str.size() / sizeof(wchar_t) - 1; +#else + charbuf = keybuf; +#endif + for(int i = 0; i < len; ++i) + { + arg_keyboard arg; + arg.ignore = false; + arg.key = charbuf[i]; + + if(context.is_alt_pressed) + { + arg.ctrl = arg.shift = false; + arg.evt_code = event_code::shortkey; + brock.set_keyboard_shortkey(true); + auto shr_wd = brock.wd_manager.find_shortkey(native_window, arg.key); + if(shr_wd) + { + arg.window_handle = reinterpret_cast(shr_wd); + brock.emit(event_code::shortkey, shr_wd, arg, true, &context); + } + continue; + } + arg.evt_code = event_code::key_char; + arg.window_handle = reinterpret_cast(msgwnd); + brock.get_key_state(arg); + + msgwnd->together.attached_events->key_char.emit(arg); + if(arg.ignore == false && brock.wd_manager.available(msgwnd)) + brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); + } + + if(brock.set_keyboard_shortkey(false)) + context.is_alt_pressed = false; + } + break; + } + brock.wd_manager.do_lazy_refresh(msgwnd, false); + if(keybuf != fixbuf) + delete [] keybuf; + } + } + break; + case KeyRelease: + nana::detail::platform_spec::instance().write_keystate(xevent.xkey); + if(context.platform.keychar != keyboard::alt) //Must NOT be an ALT + { + msgwnd = brock.focus(); + if(msgwnd) + { + arg_keyboard arg; + arg.evt_code = event_code::key_release; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = static_cast(context.platform.keychar); + brock.get_key_state(arg); + brock.emit(event_code::key_release, msgwnd, arg, true, &context); + } + } + else + { + context.is_alt_pressed = false; + brock.set_keyboard_shortkey(false); + } + break; + default: + if(message == ClientMessage) + { + auto & atoms = nana::detail::platform_spec::instance().atombase(); + if(atoms.wm_protocols == xevent.xclient.message_type) + { + if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast(xevent.xclient.data.l[0]))) + { + arg_unload arg; + arg.window_handle = reinterpret_cast(msgwnd); + arg.cancel = false; + brock.emit(event_code::unload, msgwnd, arg, true, &context); + if(false == arg.cancel) + native_interface::close_window(native_window); + } + } + } + } + + root_runtime = brock.wd_manager.root_runtime(native_window); + if(root_runtime) + { + context.event_window = pre_event_window; + root_runtime->condition.pressed = pressed_wd; + root_runtime->condition.hovered = hovered_wd; + } + else + { + auto context = brock.get_thread_context(); + if(context) context->event_window = pre_event_window; + } + + if(msgwnd) + brock.wd_manager.remove_trash_handle(::nana::system::this_thread_id()); + } + } + + void bedrock::pump_event(window modal_window, bool is_modal) + { + thread_context * context = open_thread_context(); + if(0 == context->window_count) + { + //test if there is not a window + remove_thread_context(); + return; + } + + ++(context->event_pump_ref_count); + wd_manager.internal_lock().revert(); + + native_window_type owner_native = 0; + core_window_t * owner = 0; + if(modal_window) + { + native_window_type modal = root(reinterpret_cast(modal_window)); + owner_native = native_interface::get_owner_window(modal); + if(owner_native) + { + native_interface::enable_window(owner_native, false); + owner = wd_manager.root(owner_native); + if(owner) + owner->flags.enabled = false; + } + } + + nana::detail::platform_spec::instance().msg_dispatch(modal_window ? reinterpret_cast(modal_window)->root : 0); + + if(owner_native) + { + if(owner) + owner->flags.enabled = true; + native_interface::enable_window(owner_native, true); + } + + wd_manager.internal_lock().forward(); + if(0 == --(context->event_pump_ref_count)) + { + if(0 == modal_window || 0 == context->window_count) + remove_thread_context(); + } + + }//end bedrock::event_loop + + void bedrock::thread_context_destroy(core_window_t * wd) + { + bedrock::thread_context * thr = get_thread_context(0); + if(thr && thr->event_window == wd) + thr->event_window = nullptr; + } + + void bedrock::thread_context_lazy_refresh() + { + thread_context* thrd = get_thread_context(0); + if(thrd && thrd->event_window) + { + //the state none should be tested, becuase in an event, there would be draw after an update, + //if the none is not tested, the draw after update will not be refreshed. + switch(thrd->event_window->other.upd_state) + { + case core_window_t::update_state::none: + case core_window_t::update_state::lazy: + thrd->event_window->other.upd_state = core_window_t::update_state::refresh; + default: break; + } + } + } + + //Dynamically set a cursor for a window + void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + { + if (nullptr == thrd) + thrd = get_thread_context(wd->thread_id); + + if ((cursor::arrow == cur) && !thrd->cursor.native_handle) + return; + + thrd->cursor.window = wd; + if ((thrd->cursor.native_handle == wd->root) && (cur == thrd->cursor.predef_cursor)) + return; + + auto & spec = nana::detail::platform_spec::instance(); + Display * disp = spec.open_display(); + + if (thrd->cursor.native_handle && (thrd->cursor.native_handle != wd->root)) + ::XUndefineCursor(disp, reinterpret_cast(thrd->cursor.native_handle)); + + thrd->cursor.native_handle = wd->root; + if (thrd->cursor.predef_cursor != cur) + { + thrd->cursor.predef_cursor = cur; + if (thrd->cursor.handle) + { + ::XFreeCursor(disp, thrd->cursor.handle); + thrd->cursor.handle = 0; + } + } + + if (nana::cursor::arrow == cur) + { + thrd->cursor.native_handle = nullptr; + thrd->cursor.window = nullptr; + ::XUndefineCursor(disp, reinterpret_cast(wd->root)); + } + else + { + if (!thrd->cursor.handle) + thrd->cursor.handle = ::XCreateFontCursor(disp, static_cast(cur)); + ::XDefineCursor(disp, reinterpret_cast(wd->root), thrd->cursor.handle); + } + } + + void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + { + wd->root_widget->other.attribute.root->state_cursor = cur; + wd->root_widget->other.attribute.root->state_cursor_window = wd; + set_cursor(wd, cur, thrd); + } + + void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) + { + if (!wd_manager.available(wd)) + return; + + wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow; + wd->root_widget->other.attribute.root->state_cursor_window = nullptr; + + auto pos = native_interface::cursor_position(); + auto native_handle = native_interface::find_window(pos.x, pos.y); + if (!native_handle) + return; + + native_interface::calc_window_point(native_handle, pos); + auto rev_wd = wd_manager.find_window(native_handle, pos.x, pos.y); + if (rev_wd) + set_cursor(rev_wd, rev_wd->predef_cursor, thrd); + } + + void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd) + { + auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow); + + switch(event_id) + { + case event_code::mouse_enter: + if (not_state_cur) + set_cursor(wd, wd->predef_cursor, thrd); + break; + case event_code::mouse_leave: + if (not_state_cur && (wd->predef_cursor != cursor::arrow)) + set_cursor(wd, nana::cursor::arrow, thrd); + break; + case event_code::destroy: + if (wd->root_widget->other.attribute.root->state_cursor_window == wd) + undefine_state_cursor(wd, thrd); + + if(wd == thrd->cursor.window) + set_cursor(wd, cursor::arrow, thrd); + break; + default: + break; + } + } +}//end namespace detail +}//end namespace nana diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp new file mode 100644 index 00000000..541bba9b --- /dev/null +++ b/source/gui/detail/native_window_interface.cpp @@ -0,0 +1,1369 @@ +/* + * Platform Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/native_window_interface.cpp + */ + +#include +#include PLATFORM_SPEC_HPP +#include +#if defined(NANA_WINDOWS) + #if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) + #include + #else + #include + #endif + #include + #include +#elif defined(NANA_X11) + #include + #include GUI_BEDROCK_HPP +#endif + +namespace nana{ + namespace paint + { + class image_accessor + { + public: +#if defined(NANA_WINDOWS) + static HICON icon(const nana::paint::image& img) + { + paint::detail::image_ico * ico = dynamic_cast(img.image_ptr_.get()); + if(ico && ico->ptr()) + return *(ico->ptr()); + return 0; + } +#endif + }; + } + + namespace detail{ + +#if defined(NANA_WINDOWS) + class tray_manager + { + struct window_extra_t + { + HICON ico; + + window_extra_t() + : ico(0) + {} + }; + + typedef std::map map_t; + + private: + tray_manager(){} + public: + typedef window_extra_t extra_t; + + static tray_manager& instance() + { + static tray_manager object; + return object; + } + + bool remove(native_window_type wd, extra_t & ext) + { + std::lock_guard lock(mutex_); + + auto i = const_cast(map_).find(wd); + if(i != map_.cend()) + { + ext = i->second; + map_.erase(i); + return true; + } + return false; + } + + HICON set_icon(native_window_type wd, HICON ico) + { + std::lock_guard lock(mutex_); + + auto i = map_.find(wd); + if(i != map_.end()) + { + HICON ret = i->second.ico; + i->second.ico = ico; + return ret; + } + + map_[wd].ico = ico; + return 0; + } + private: + std::recursive_mutex mutex_; + map_t map_; + }; + + + //This function is a proxy for ShowWindow/ShowWindowAsync + //It determines which API should be called. + void msw_show_window(HWND wd, int cmd) + { + bool async = true; + const DWORD tid = ::GetCurrentThreadId(); + if(tid == ::GetWindowThreadProcessId(wd, nullptr)) + { + HWND owner = ::GetWindow(wd, GW_OWNER); + if ((nullptr == owner) || (tid == ::GetWindowThreadProcessId(owner, nullptr))) + { + async = false; + HWND owned = ::GetWindow(wd, GW_HWNDPREV); + while (owned) + { + if (::GetWindow(owned, GW_OWNER) == wd) + { + if (tid != ::GetWindowThreadProcessId(owned, nullptr)) + { + async = true; + break; + } + } + owned = ::GetWindow(owned, GW_HWNDPREV); + } + } + } + if (async) + ::ShowWindowAsync(wd, cmd); + else + ::ShowWindow(wd, cmd); + } +#elif defined(NANA_X11) + namespace restrict + { + nana::detail::platform_spec & spec = nana::detail::platform_spec::instance(); + } +#endif + + //struct native_interface + nana::size native_interface::screen_size() + { +#if defined(NANA_WINDOWS) + return nana::size(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN)); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + Screen* s = ::XScreenOfDisplay(restrict::spec.open_display(), ::XDefaultScreen(restrict::spec.open_display())); + return nana::size(::XWidthOfScreen(s), ::XHeightOfScreen(s)); +#endif + } + + rectangle native_interface::screen_area_from_point(const point& pos) + { +#if defined(NANA_WINDOWS) + typedef HMONITOR (__stdcall * MonitorFromPointT)(POINT,DWORD); + + MonitorFromPointT mfp = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("User32.DLL"), "MonitorFromPoint")); + if(mfp) + { + POINT native_pos = {pos.x, pos.y}; + HMONITOR monitor = mfp(native_pos, 2 /*MONITOR_DEFAULTTONEAREST*/); + + MONITORINFO mi; + mi.cbSize = sizeof mi; + if(::GetMonitorInfo(monitor, &mi)) + { + return rectangle(mi.rcWork.left, mi.rcWork.top, + mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top); + } + } +#elif defined(NANA_X11) +#endif + return screen_size(); + } + + + + //platform-dependent + native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app) + { +#if defined(NANA_WINDOWS) + DWORD style = WS_SYSMENU | WS_CLIPCHILDREN; + DWORD style_ex= WS_EX_NOPARENTNOTIFY; + + if(app.minimize) style |= WS_MINIMIZEBOX; + if(app.maximize) style |= WS_MAXIMIZEBOX; + + if(app.sizable) style |= WS_THICKFRAME; + + if(app.decoration) + style |= WS_OVERLAPPED | WS_CAPTION; + + style |= (nested ? WS_CHILD : WS_POPUP); + style_ex |= (app.taskbar ? WS_EX_APPWINDOW : WS_EX_TOOLWINDOW); + + if(app.floating) style_ex |= WS_EX_TOPMOST; + + POINT pt = {r.x, r.y}; + + if(owner && (nested == false)) + ::ClientToScreen(reinterpret_cast(owner), &pt); + + HWND wnd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"), + style, + pt.x, pt.y, 100, 100, + reinterpret_cast(owner), 0, ::GetModuleHandle(0), 0); + + //A window may have a border, this should be adjusted the client area fit for the specified size. + ::RECT client; + ::GetClientRect(wnd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area + ::RECT wd_area; + ::GetWindowRect(wnd, &wd_area); + wd_area.right -= wd_area.left; + wd_area.bottom -= wd_area.top; + if(nested) + { + wd_area.left = pt.x; + wd_area.top = pt.y; + } + + int delta_w = static_cast(r.width) - client.right; + int delta_h = static_cast(r.height) - client.bottom; + + ::MoveWindow(wnd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); + + ::GetClientRect(wnd, &client); + ::GetWindowRect(wnd, &wd_area); + wd_area.right -= wd_area.left; + wd_area.bottom -= wd_area.top; + + window_result result = {reinterpret_cast(wnd), + static_cast(client.right), static_cast(client.bottom), + static_cast(wd_area.right - client.right), static_cast(wd_area.bottom - client.bottom)}; +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + + XSetWindowAttributes win_attr; + unsigned long attr_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | + CWWinGravity | CWBitGravity | CWColormap | CWEventMask; + + Display * disp = restrict::spec.open_display(); + win_attr.colormap = restrict::spec.colormap(); + + win_attr.background_pixmap = None; + win_attr.background_pixel = 0xFFFFFF; + win_attr.border_pixmap = None; + win_attr.border_pixel = 0x0; + win_attr.bit_gravity = 0; + win_attr.win_gravity = NorthWestGravity; + win_attr.backing_store = 0; + win_attr.backing_planes = 0; + win_attr.backing_pixel = 0; + win_attr.colormap = restrict::spec.colormap(); + + if(app.decoration == false) + { + win_attr.override_redirect = True; + attr_mask |= CWOverrideRedirect; + } + + Window parent = (owner ? reinterpret_cast(owner) : restrict::spec.root_window()); + nana::point pos(r.x, r.y); + if((false == nested) && owner) + { + win_attr.save_under = True; + attr_mask |= CWSaveUnder; + parent = restrict::spec.root_window(); + calc_screen_point(owner, pos); + } + + win_attr.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask; + + Window handle = ::XCreateWindow(disp, parent, + pos.x, pos.y, (r.width ? r.width : 1), (r.height ? r.height : 1), 0, + restrict::spec.screen_depth(), InputOutput, restrict::spec.screen_visual(), + attr_mask, &win_attr); + if(handle) + { + if(owner) + restrict::spec.make_owner(owner, reinterpret_cast(handle)); + + XTextProperty name; + char text[] = "Nana Window"; + char * str = text; + ::XStringListToTextProperty(&str, 1, &name); + ::XSetWMName(disp, handle, &name); + + const nana::detail::atombase_tag & ab = restrict::spec.atombase(); + ::XSetWMProtocols(disp, handle, const_cast(&ab.wm_delete_window), 1); + + struct + { + long flags; + long functions; + long decorations; + long input; + long status; + }motif; + //MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;// | MWM_HINTS_INPUT_MODE; + motif.flags = 1 | 2; //| 4; + motif.functions = 4;//MWM_FUNC_MOVE; + motif.decorations = 0; + motif.input = 0;//MWM_INPUT_MODELESS; + motif.status = 0; + + XSizeHints hints; + hints.flags = USPosition; + hints.x = pos.x; + hints.y = pos.y; + + if(app.sizable) + { + motif.decorations |= 4; //MWM_DECOR_RESIZEH; + motif.functions |= 2; //MWM_FUNC_RESIZE; + } + else + { + hints.min_width = hints.max_width = r.width; + hints.min_height = hints.max_height = r.height; + hints.flags |= (PMinSize | PMaxSize); + } + ::XSetWMNormalHints(disp, handle, &hints); + + if(app.decoration) + { + if(app.minimize) + { + motif.decorations |= (1 << 5); //MWM_DECOR_MINIMIZE; + motif.functions |= (1 << 3); //MWM_FUNC_MINIMIZE; + } + + if(app.maximize) + { + motif.decorations |= (1 << 6);//MWM_DECOR_MAXIMIZE; + motif.functions |= ( 1 << 4);//MWM_FUNC_MAXIMIZE; + } + motif.functions |= (1<<5); //MWM_FUNC_CLOSE + motif.decorations |= (2) | 8; //MWM_DECOR_BORDER | MWM_DECOR_TITLE + } + + if((false == nested) && owner) + { + ::XChangeProperty(disp, handle, ab.net_wm_window_type, XA_ATOM, 32, PropModeReplace, + reinterpret_cast(const_cast(&ab.net_wm_window_type_dialog)), 1); + ::XSetTransientForHint(disp, handle, reinterpret_cast(owner)); + } + + ::XChangeProperty(disp, handle, ab.motif_wm_hints, ab.motif_wm_hints, 32, PropModeReplace, + reinterpret_cast(&motif), sizeof(motif)/sizeof(long)); + + if(app.floating) + { + ::XChangeProperty(disp, handle, ab.net_wm_window_type, XA_ATOM, 32, PropModeReplace, + reinterpret_cast(const_cast(&ab.net_wm_window_type_normal)), 1); + ::XSetTransientForHint(disp, handle, restrict::spec.root_window()); + } + + if(false == app.taskbar) + { + ::XChangeProperty(disp, handle, ab.net_wm_state, XA_ATOM, 32, PropModeAppend, + reinterpret_cast(const_cast(&ab.net_wm_state_skip_taskbar)), 1); + } + } + window_result result = {reinterpret_cast(handle), r.width, r.height, 0, 0}; + restrict::spec.msg_insert(reinterpret_cast(handle)); +#endif + return result; + } + + native_window_type native_interface::create_child_window(native_window_type parent, const rectangle& r) + { + if(nullptr == parent) return nullptr; +#if defined(NANA_WINDOWS) + HWND handle = ::CreateWindowEx(WS_EX_CONTROLPARENT, // Extended possibilites for variation + STR("NanaWindowInternal"), + STR("Nana Child Window"), // Title Text + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS, + r.x, r.y, r.width, r.height, + reinterpret_cast(parent), // The window is a child-window to desktop + 0, ::GetModuleHandle(0), 0); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + + XSetWindowAttributes win_attr; + unsigned long attr_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | + CWWinGravity | CWBitGravity | CWColormap | CWEventMask; + + Display * disp = restrict::spec.open_display(); + win_attr.colormap = restrict::spec.colormap(); + + win_attr.background_pixmap = None; + win_attr.background_pixel = 0xFFFFFF; + win_attr.border_pixmap = None; + win_attr.border_pixel = 0x0; + win_attr.bit_gravity = 0; + win_attr.win_gravity = NorthWestGravity; + win_attr.backing_store = 0; + win_attr.backing_planes = 0; + win_attr.backing_pixel = 0; + win_attr.colormap = restrict::spec.colormap(); + + win_attr.override_redirect = True; + attr_mask |= CWOverrideRedirect; + + nana::point pos(r.x, r.y); + win_attr.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask; + + Window handle = ::XCreateWindow(disp, reinterpret_cast(parent), + pos.x, pos.y, (r.width ? r.width : 1), (r.height ? r.height : 1), 0, + restrict::spec.screen_depth(), InputOutput, restrict::spec.screen_visual(), + attr_mask, &win_attr); + + if(handle) + { + restrict::spec.make_owner(parent, reinterpret_cast(handle)); + + XTextProperty name; + char text[] = "Nana Child Window"; + char * str = text; + ::XStringListToTextProperty(&str, 1, &name); + ::XSetWMName(disp, handle, &name); + + const nana::detail::atombase_tag & ab = restrict::spec.atombase(); + ::XSetWMProtocols(disp, handle, const_cast(&ab.wm_delete_window), 1); + + struct + { + long flags; + long functions; + long decorations; + long input; + long status; + }motif; + //MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;// | MWM_HINTS_INPUT_MODE; + motif.flags = 1 | 2; //| 4; + motif.functions = 4;//MWM_FUNC_MOVE; + motif.decorations = 0; + motif.input = 0;//MWM_INPUT_MODELESS; + motif.status = 0; + + XSizeHints hints; + hints.flags = USPosition; + hints.x = pos.x; + hints.y = pos.y; + hints.min_width = hints.max_width = r.width; + hints.min_height = hints.max_height = r.height; + hints.flags |= (PMinSize | PMaxSize); + ::XSetWMNormalHints(disp, handle, &hints); + + ::XChangeProperty(disp, handle, ab.motif_wm_hints, ab.motif_wm_hints, 32, PropModeReplace, + reinterpret_cast(&motif), sizeof(motif)/sizeof(long)); + + ::XChangeProperty(disp, handle, ab.net_wm_state, XA_ATOM, 32, PropModeAppend, + reinterpret_cast(const_cast(&ab.net_wm_state_skip_taskbar)), 1); + } +#endif + return reinterpret_cast(handle); + } + +#if defined(NANA_X11) + void native_interface::set_modal(native_window_type wd) + { + Window owner = reinterpret_cast(restrict::spec.get_owner(wd)); + if(wd && owner) + { + if(is_window_visible(wd)) + show_window(wd, false, true); + auto disp = restrict::spec.open_display(); + auto & atombase = restrict::spec.atombase(); + ::XSetTransientForHint(disp, reinterpret_cast(wd), owner); + ::XChangeProperty(disp, reinterpret_cast(wd), + atombase.net_wm_state, XA_ATOM, sizeof(int) * 8, + PropModeReplace, + reinterpret_cast(&atombase.net_wm_state_modal), 1); + } + } +#endif + + void native_interface::enable_dropfiles(native_window_type wd, bool enb) + { +#if defined(NANA_WINDOWS) + ::DragAcceptFiles(reinterpret_cast(wd), enb); +#else + int dndver = (enb ? 4: 0); + ::XChangeProperty(restrict::spec.open_display(), reinterpret_cast(wd), restrict::spec.atombase().xdnd_aware, XA_ATOM, sizeof(int) * 8, + PropModeReplace, reinterpret_cast(&dndver), 1); +#endif + } + + void native_interface::enable_window(native_window_type wd, bool is_enabled) + { +#if defined(NANA_WINDOWS) + ::EnableWindow(reinterpret_cast(wd), is_enabled); +#else + int mask = ExposureMask | StructureNotifyMask; + if(is_enabled) + { + mask |= (ButtonPressMask | ButtonReleaseMask | PointerMotionMask); + mask |= (KeyPressMask | KeyReleaseMask); + mask |= (EnterWindowMask | LeaveWindowMask | FocusChangeMask); + } + + ::XSelectInput(restrict::spec.open_display(), reinterpret_cast(wd), mask); +#endif + } + + bool native_interface::window_icon(native_window_type wd, const nana::paint::image& img) + { +#if defined(NANA_WINDOWS) + HICON ico = paint::image_accessor::icon(img); + if(ico) + { + nana::detail::platform_spec::instance().keep_window_icon(wd, img); + ::SendMessage(reinterpret_cast(wd), WM_SETICON, ICON_BIG, reinterpret_cast(ico)); + ::SendMessage(reinterpret_cast(wd), WM_SETICON, ICON_SMALL, reinterpret_cast(ico)); + return true; + } +#elif defined(NANA_X11) + if(wd && (false == img.empty())) + { + + const nana::paint::graphics & graph = restrict::spec.keep_window_icon(wd, img); + XWMHints hints; + hints.flags = IconPixmapHint; + hints.icon_pixmap = graph.handle()->pixmap; + + nana::detail::platform_scope_guard psg; + ::XSetWMHints(restrict::spec.open_display(), reinterpret_cast(wd), &hints); + return true; + } +#endif + return false; + } + + void native_interface::activate_owner(native_window_type wd) + { +#if defined(NANA_WINDOWS) + activate_window(reinterpret_cast( + ::GetWindow(reinterpret_cast(wd), GW_OWNER) + )); +#endif + } + + void native_interface::activate_window(native_window_type wd) + { +#if defined(NANA_WINDOWS) + auto native_wd = reinterpret_cast(wd); + if (::IsWindow(native_wd)) + { + if (::GetWindowThreadProcessId(native_wd, nullptr) == ::GetCurrentThreadId()) + { + ::EnableWindow(native_wd, true); + ::SetActiveWindow(native_wd); + } + else + ::PostMessage(native_wd, nana::detail::messages::async_activate, 0, 0); + } +#endif + } + + //close_window + //Destroy a window + void native_interface::close_window(native_window_type wd) + { +#if defined(NANA_WINDOWS) + if(wd && (::DestroyWindow(reinterpret_cast(wd)) == false)) + { + //DestroyWindow would be failed if the calling thread is not the window thread + //It should send a WM_DESTROY message into window thread for destroying window + if(::GetLastError() == ERROR_ACCESS_DENIED) + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_destroy_window, 0, 0); + } +#elif defined(NANA_X11) + //Under X, XDestroyWindow destroys the specified window and generats a DestroyNotify + //event, when the client receives the event, the specified window has been already + //destroyed. This is a feature which is different from Windows. So the following + //works should be handled before calling XDestroyWindow. + auto & bedrock = bedrock::instance(); + if(wd == bedrock.get_menu()) + bedrock.empty_menu(); + + Display* disp = restrict::spec.open_display(); + restrict::spec.remove(wd); + auto iwd = bedrock.wd_manager.root(wd); + if(iwd) + { + { + //Before calling window_manager::destroy, make sure the window is invisible. + //It is a behavior like Windows. + nana::detail::platform_scope_guard psg; + restrict::spec.set_error_handler(); + ::XUnmapWindow(disp, reinterpret_cast(wd)); + ::XFlush(disp); + restrict::spec.rev_error_handler(); + } + bedrock.wd_manager.destroy(iwd); + bedrock.rt_manager.remove_if_exists(iwd); + bedrock.wd_manager.destroy_handle(iwd); + } + + nana::detail::platform_scope_guard psg; + restrict::spec.set_error_handler(); + ::XDestroyWindow(disp, reinterpret_cast(wd)); + restrict::spec.rev_error_handler(); +#endif + } + + void native_interface::show_window(native_window_type wd, bool show, bool active) + { +#if defined(NANA_WINDOWS) + int cmd = (show ? (active ? SW_SHOW : SW_SHOWNA) : SW_HIDE); + msw_show_window(reinterpret_cast(wd), cmd); +#elif defined(NANA_X11) + if(wd) + { + nana::detail::platform_scope_guard psg; + Display* disp = restrict::spec.open_display(); + if(show) + { + ::XMapWindow(disp, reinterpret_cast(wd)); + Window grab = restrict::spec.grab(0); + if(grab == reinterpret_cast(wd)) + capture_window(wd, true); + } + else + ::XUnmapWindow(disp, reinterpret_cast(wd)); + + ::XFlush(disp); + } +#endif + } + + void native_interface::restore_window(native_window_type wd) + { +#if defined(NANA_WINDOWS) + msw_show_window(reinterpret_cast(wd), SW_RESTORE); +#elif defined(NANA_X11) + //Restore the window by removing NET_WM_STATE_MAXIMIZED_HORZ, + //_NET_WM_STATE_MAXIMIZED_VERT and _NET_WM_STATE_FULLSCREEN. + Display * disp = restrict::spec.open_display(); + Window default_root = XDefaultRootWindow(disp); + const nana::detail::atombase_tag & atombase = restrict::spec.atombase(); + XEvent evt; + evt.xclient.type = ClientMessage; + evt.xclient.display = restrict::spec.open_display(); + evt.xclient.message_type = atombase.net_wm_state; + evt.xclient.format = 32; + evt.xclient.window = reinterpret_cast(wd); + evt.xclient.data.l[0] = 0; //_NET_WM_STATE_REMOVE + evt.xclient.data.l[1] = atombase.net_wm_state_maximized_horz; + evt.xclient.data.l[2] = atombase.net_wm_state_maximized_vert; + evt.xclient.data.l[3] = evt.xclient.data.l[4] = 0; + + nana::detail::platform_scope_guard psg; + ::XSendEvent(disp, default_root, False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + evt.xclient.data.l[1] = atombase.net_wm_state_fullscreen; + evt.xclient.data.l[2] = 0; + ::XSendEvent(disp, default_root, False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + + //Transfer the window from IconState to NormalState. + evt.xclient.message_type = atombase.wm_change_state; + evt.xclient.data.l[0] = NormalState; + evt.xclient.data.l[1] = 0; + ::XSendEvent(disp, default_root, False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + ::XMapWindow(disp, reinterpret_cast(wd)); + restrict::spec.set_error_handler(); + ::XSetInputFocus(disp, reinterpret_cast(wd), RevertToPointerRoot, CurrentTime); +#endif + } + + void native_interface::zoom_window(native_window_type wd, bool ask_for_max) + { +#if defined(NANA_WINDOWS) + msw_show_window(reinterpret_cast(wd), ask_for_max ? SW_MAXIMIZE : SW_MINIMIZE); +#elif defined(NANA_X11) + Display * disp = restrict::spec.open_display(); + if (ask_for_max) + { + const nana::detail::atombase_tag & atombase = restrict::spec.atombase(); + XEvent evt; + evt.xclient.type = ClientMessage; + evt.xclient.display = restrict::spec.open_display(); + evt.xclient.message_type = atombase.net_wm_state; + evt.xclient.format = 32; + evt.xclient.window = reinterpret_cast(wd); + evt.xclient.data.l[0] = 1; //_NET_WM_STATE_ADD + evt.xclient.data.l[1] = atombase.net_wm_state_maximized_horz; + evt.xclient.data.l[2] = atombase.net_wm_state_maximized_vert; + evt.xclient.data.l[3] = evt.xclient.data.l[4] = 0; + + nana::detail::platform_scope_guard psg; + ::XSendEvent(disp, XDefaultRootWindow(disp), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + ::XMapWindow(disp, reinterpret_cast(wd)); + } + else + ::XIconifyWindow(disp, reinterpret_cast(wd), XDefaultScreen(disp)); +#endif + } + + void native_interface::refresh_window(native_window_type wd) + { +#if defined(NANA_WINDOWS) + ::InvalidateRect(reinterpret_cast(wd), nullptr, true); +#elif defined(NANA_X11) +#endif + } + + bool native_interface::is_window(native_window_type wd) + { +#if defined(NANA_WINDOWS) + return (FALSE != ::IsWindow(reinterpret_cast(wd))); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + XWindowAttributes attr; + restrict::spec.set_error_handler(); + ::XGetWindowAttributes(restrict::spec.open_display(), reinterpret_cast(wd), &attr); + return (BadWindow != restrict::spec.rev_error_handler()); +#endif + } + + bool native_interface::is_window_visible(native_window_type wd) + { +#if defined(NANA_WINDOWS) + return (FALSE != ::IsWindowVisible(reinterpret_cast(wd))); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + XWindowAttributes attr; + restrict::spec.set_error_handler(); + ::XGetWindowAttributes(restrict::spec.open_display(), reinterpret_cast(wd), &attr); + return (BadWindow != restrict::spec.rev_error_handler() && + attr.map_state != IsUnmapped); +#endif + } + + bool native_interface::is_window_zoomed(native_window_type wd, bool ask_for_max) + { +#if defined(NANA_WINDOWS) + return (FALSE != (ask_for_max ? ::IsZoomed(reinterpret_cast(wd)) : ::IsIconic(reinterpret_cast(wd)))); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + bool zoomed = false; + unsigned long n,i; Atom type; unsigned char *prop; int format; + if(Success== ::XGetWindowProperty(restrict::spec.open_display(), reinterpret_cast(wd), restrict::spec.atombase().net_wm_state, 0, 2, false, AnyPropertyType, &type, &format, &n, &i, &prop)) + { + if(32 == format) + { + if(ask_for_max) + { + if(type == XA_ATOM) + { + for(i=0; i(prop)[i] == restrict::spec.atombase().net_wm_state_fullscreen) + { + zoomed = true; + break; + } + } + } + } + else + zoomed = (IconicState == *reinterpret_cast(prop)); + } + XFree(prop); + } + return zoomed; +#endif + } + + nana::point native_interface::window_position(native_window_type wd) + { +#if defined(NANA_WINDOWS) + ::RECT r; + ::GetWindowRect(reinterpret_cast(wd), & r); + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + if(owner) + { + ::POINT pos = {r.left, r.top}; + ::ScreenToClient(owner, &pos); + return nana::point(pos.x, pos.y); + } + return nana::point(r.left, r.top); +#elif defined(NANA_X11) + int x, y; + nana::detail::platform_scope_guard psg; + Window root = reinterpret_cast(restrict::spec.get_owner(wd)); + if(root == 0) root = restrict::spec.root_window(); + Window child; + if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), root, 0, 0, &x, &y, &child)) + return nana::point(x, y); + return nana::point(0, 0); +#endif + } + + void native_interface::move_window(native_window_type wd, int x, int y) + { +#if defined(NANA_WINDOWS) + if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + { + nana::detail::messages::move_window * mw = new nana::detail::messages::move_window; + mw->x = x; + mw->y = y; + mw->ignore = mw->Size; + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0); + } + else + { + ::RECT r; + ::GetWindowRect(reinterpret_cast(wd), &r); + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + if(owner) + { + ::RECT owner_rect; + ::GetWindowRect(owner, &owner_rect); + ::POINT pos = {owner_rect.left, owner_rect.top}; + ::ScreenToClient(owner, &pos); + x += (owner_rect.left - pos.x); + y += (owner_rect.top - pos.y); + } + ::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true); + } +#elif defined(NANA_X11) + Display * disp = restrict::spec.open_display(); + + nana::detail::platform_scope_guard psg; + Window owner = reinterpret_cast(restrict::spec.get_owner(wd)); + if(owner) + { + Window child; + ::XTranslateCoordinates(disp, owner, restrict::spec.root_window(), + x, y, &x, &y, &child); + } + + XWindowAttributes attr; + ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); + if(attr.map_state == IsUnmapped) + { + XSizeHints hints; + hints.flags = USPosition; + hints.x = x; + hints.y = y; + ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); + } + + ::XMoveWindow(disp, reinterpret_cast(wd), x, y); +#endif + } + + void native_interface::move_window(native_window_type wd, const rectangle& r) + { +#if defined(NANA_WINDOWS) + if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + { + auto * mw = new nana::detail::messages::move_window; + mw->x = r.x; + mw->y = r.y; + mw->width = r.width; + mw->height = r.height; + mw->ignore = 0; + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0); + } + else + { + int x = r.x; + int y = r.y; + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + if(owner) + { + ::RECT owner_rect; + ::GetWindowRect(owner, &owner_rect); + ::POINT pos = {owner_rect.left, owner_rect.top}; + ::ScreenToClient(owner, &pos); + x += (owner_rect.left - pos.x); + y += (owner_rect.top - pos.y); + } + + RECT client, wd_area; + ::GetClientRect(reinterpret_cast(wd), &client); + ::GetWindowRect(reinterpret_cast(wd), &wd_area); + unsigned ext_w = (wd_area.right - wd_area.left) - client.right; + unsigned ext_h = (wd_area.bottom - wd_area.top) - client.bottom; + ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true); + } +#elif defined(NANA_X11) + Display * disp = restrict::spec.open_display(); + long supplied; + XSizeHints hints; + nana::detail::platform_scope_guard psg; + + ::XGetWMNormalHints(disp, reinterpret_cast(wd), &hints, &supplied); + if((hints.flags & (PMinSize | PMaxSize)) && (hints.min_width == hints.max_width) && (hints.min_height == hints.max_height)) + { + hints.flags = PMinSize | PMaxSize; + hints.min_width = hints.max_width = r.width; + hints.min_height = hints.max_height = r.height; + } + else + hints.flags = 0; + + Window owner = reinterpret_cast(restrict::spec.get_owner(wd)); + int x = r.x; + int y = r.y; + if(owner) + { + Window child; + ::XTranslateCoordinates(disp, owner, restrict::spec.root_window(), + r.x, r.y, &x, &y, &child); + } + + XWindowAttributes attr; + ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); + if(attr.map_state == IsUnmapped) + { + hints.flags |= (USPosition | USSize); + hints.x = x; + hints.y = y; + hints.width = r.width; + hints.height = r.height; + } + + if(hints.flags) + ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); + + ::XMoveResizeWindow(disp, reinterpret_cast(wd), x, y, r.width, r.height); +#endif + } + + void native_interface::bring_to_top(native_window_type wd) + { +#if defined(NANA_WINDOWS) + HWND native_wd = reinterpret_cast(wd); + + if (FALSE == ::IsWindow(native_wd)) + return; + + HWND fg_wd = ::GetForegroundWindow(); + DWORD fg_tid = ::GetWindowThreadProcessId(fg_wd, nullptr); + ::AttachThreadInput(::GetCurrentThreadId(), fg_tid, TRUE); + ::ShowWindow(native_wd, SW_SHOWNORMAL); + ::SetWindowPos(native_wd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + ::SetWindowPos(native_wd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + ::AttachThreadInput(::GetCurrentThreadId(), fg_tid, FALSE); +#else + set_window_z_order(wd, nullptr, z_order_action::top); +#endif + } + + void native_interface::set_window_z_order(native_window_type wd, native_window_type wd_after, z_order_action action_if_no_wd_after) + { +#if defined(NANA_WINDOWS) + HWND wa = reinterpret_cast(wd_after); + if(wa == 0) + { + switch(action_if_no_wd_after) + { + case z_order_action::bottom : wa = HWND_BOTTOM; break; + case z_order_action::top: wa = HWND_TOP; break; + case z_order_action::topmost: wa = HWND_TOPMOST; break; + case z_order_action::foreground: + ::SetForegroundWindow(reinterpret_cast(wd)); + return; + default: + wa = HWND_NOTOPMOST; + } + } + if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_set_window_pos, reinterpret_cast(wa), SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + else + ::SetWindowPos(reinterpret_cast(wd), wa, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + Display * disp = restrict::spec.open_display(); + if(0 == wd_after) + { + switch(action_if_no_wd_after) + { + case z_order_action::bottom: + ::XLowerWindow(disp, reinterpret_cast(wd)); + break; + case z_order_action::foreground: + case z_order_action::top: + case z_order_action::topmost: + ::XRaiseWindow(disp, reinterpret_cast(wd)); + break; + default: //z_order_action::none + break; + } + } + else + { + //If the handle wd is a top level, XConfigureWindow() will be failed with a BadMatch. + //The fix is to use XReconfigureWMWindow() instead. + + XWindowChanges values; + values.sibling = reinterpret_cast(wd_after); + values.stack_mode = Below; + ::XReconfigureWMWindow(disp, reinterpret_cast(wd), ::XDefaultScreen(disp), CWSibling | CWStackMode, &values); + } +#endif + } + + void native_interface::window_size(native_window_type wd, const size& sz) + { +#if defined(NANA_WINDOWS) + if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + { + auto * mw = new nana::detail::messages::move_window; + mw->width = sz.width; + mw->height = sz.height; + mw->ignore = mw->Pos; + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0); + } + else + { + ::RECT r; + ::GetWindowRect(reinterpret_cast(wd), &r); + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + HWND parent = ::GetParent(reinterpret_cast(wd)); + if(parent && (parent != owner)) + { + ::POINT pos = {r.left, r.top}; + ::ScreenToClient(parent, &pos); + r.left = pos.x; + r.top = pos.y; + } + ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true); + } +#elif defined(NANA_X11) + auto disp = restrict::spec.open_display(); + nana::detail::platform_scope_guard psg; + + //Check the XSizeHints for testing whether the window is sizable. + XSizeHints hints; + long supplied; + ::XGetWMNormalHints(disp, reinterpret_cast(wd), &hints, &supplied); + if((hints.flags & (PMinSize | PMaxSize)) && (hints.min_width == hints.max_width) && (hints.min_height == hints.max_height)) + { + hints.flags = PMinSize | PMaxSize; + hints.min_width = hints.max_width = sz.width; + hints.min_height = hints.max_height = sz.height; + ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); + } + ::XResizeWindow(disp, reinterpret_cast(wd), sz.width, sz.height); +#endif + } + + void native_interface::get_window_rect(native_window_type wd, rectangle& r) + { +#if defined(NANA_WINDOWS) + ::RECT winr; + ::GetWindowRect(reinterpret_cast(wd), &winr); + r.x = winr.left; + r.y = winr.top; + r.width = winr.right - winr.left; + r.height = winr.bottom - winr.top; +#elif defined(NANA_X11) + Window root; + int x, y; + unsigned border, depth; + nana::detail::platform_scope_guard psg; + ::XGetGeometry(restrict::spec.open_display(), reinterpret_cast(wd), &root, &x, &y, &r.width, &r.height, &border, &depth); +#endif + } + + void native_interface::window_caption(native_window_type wd, const nana::string& title) + { +#if defined(NANA_WINDOWS) + if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) + { + wchar_t * wstr; +#if defined(NANA_UNICODE) + wstr = new wchar_t[title.length() + 1]; + wcscpy(wstr, title.c_str()); +#else + std::wstring str = nana::charset(title); + wstr = new wchar_t[str.length() + 1]; + wcscpy(wstr, str.c_str()); +#endif + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_set_window_text, reinterpret_cast(wstr), 0); + } + else + ::SetWindowText(reinterpret_cast(wd), title.c_str()); +#elif defined(NANA_X11) + ::XTextProperty name; + #if defined(NANA_UNICODE) + std::string mbstr = nana::charset(title); + char* text = const_cast(mbstr.c_str()); + #else + char* text = const_cast(title.c_str()); + #endif + nana::detail::platform_scope_guard psg; + ::XStringListToTextProperty(&text, 1, &name); + ::XSetWMName(restrict::spec.open_display(), reinterpret_cast(wd), &name); +#endif + } + + nana::string native_interface::window_caption(native_window_type wd) + { +#if defined(NANA_WINDOWS) + int length = ::GetWindowTextLength(reinterpret_cast(wd)); + if(length > 0) + { + nana::string str; + //One for NULL terminator which GetWindowText will write. + str.resize(length+1); + + ::GetWindowText(reinterpret_cast(wd), &(str[0]), static_cast(str.size())); + + //Remove the null terminator writtien by GetWindowText + str.resize(length); + + return str; + } + return nana::string(); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + ::XTextProperty txtpro; + if(::XGetWMName(restrict::spec.open_display(), reinterpret_cast(wd), &txtpro)) + { + char ** strlist; + int size; + if(::XTextPropertyToStringList(&txtpro, &strlist, &size)) + { + if(size > 1) + { + nana::string str = nana::charset(*strlist); + ::XFreeStringList(strlist); + return str; + } + } + } + return nana::string(); +#endif + } + + void native_interface::capture_window(native_window_type wd, bool cap) + { +#if defined(NANA_WINDOWS) + if(cap) + ::SetCapture(reinterpret_cast(wd)); + else + ::ReleaseCapture(); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + if(cap) + { + const unsigned mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask; + if(GrabNotViewable == ::XGrabPointer(restrict::spec.open_display(), reinterpret_cast(wd), false, mask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime)) + { + restrict::spec.grab(reinterpret_cast(wd)); + } + } + else + { + ::XUngrabPointer(restrict::spec.open_display(), CurrentTime); + ::XFlush(restrict::spec.open_display()); + restrict::spec.grab(0); + } +#endif + } + + nana::point native_interface::cursor_position() + { +#if defined(NANA_WINDOWS) + POINT point; + ::GetCursorPos(&point); + return nana::point(point.x, point.y); +#elif defined(NANA_X11) + nana::point pos; + Window drop_wd; + int x, y; + unsigned mask; + nana::detail::platform_scope_guard psg; + ::XQueryPointer(restrict::spec.open_display(), restrict::spec.root_window(), &drop_wd, &drop_wd, &pos.x, &pos.y, &x, &y, &mask); + return pos; +#endif + } + + native_window_type native_interface::get_owner_window(native_window_type wd) + { +#if defined(NANA_WINDOWS) + return reinterpret_cast(::GetWindow(reinterpret_cast(wd), GW_OWNER)); +#elif defined(NANA_X11) + return restrict::spec.get_owner(wd); +#endif + } + + void native_interface::caret_create(native_window_type wd, unsigned width, unsigned height) + { +#if defined(NANA_WINDOWS) + ::CreateCaret(reinterpret_cast(wd), 0, int(width), int(height)); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + restrict::spec.caret_open(wd, width, height); +#endif + } + + void native_interface::caret_destroy(native_window_type wd) + { +#if defined(NANA_WINDOWS) + if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::operate_caret, 1, 0); + else + ::DestroyCaret(); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + restrict::spec.caret_close(wd); +#endif + } + + void native_interface::caret_pos(native_window_type wd, int x, int y) + { +#if defined(NANA_WINDOWS) + if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) + { + auto cp = new nana::detail::messages::caret; + cp->x = x; + cp->y = y; + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::operate_caret, 2, reinterpret_cast(cp)); + } + else + ::SetCaretPos(x, y); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + restrict::spec.caret_pos(wd, x, y); +#endif + } + + void native_interface::caret_visible(native_window_type wd, bool vis) + { +#if defined(NANA_WINDOWS) + (vis ? ::ShowCaret : ::HideCaret)(reinterpret_cast(wd)); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + restrict::spec.caret_visible(wd, vis); +#endif + } + + void native_interface::set_focus(native_window_type wd) + { +#if defined(NANA_WINDOWS) + if(wd && (::GetFocus() != reinterpret_cast(wd))) + { + if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), nullptr)) + ::PostMessage(reinterpret_cast(wd), nana::detail::messages::async_set_focus, 0, 0); + else + ::SetFocus(reinterpret_cast(wd)); + } +#elif defined(NANA_X11) + nana::detail::platform_scope_guard lock; + XWindowAttributes attr; + ::XGetWindowAttributes(restrict::spec.open_display(), reinterpret_cast(wd), &attr); + //Make sure the window is mapped before setting focus. + if(IsViewable == attr.map_state) + ::XSetInputFocus(restrict::spec.open_display(), reinterpret_cast(wd), RevertToPointerRoot, CurrentTime); +#endif + } + + native_window_type native_interface::get_focus_window() + { +#if defined(NANA_WINDOWS) + return reinterpret_cast(::GetFocus()); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + Window wd; + int revert; + ::XGetInputFocus(restrict::spec.open_display(), &wd, &revert); + return reinterpret_cast(wd); +#endif + } + + bool native_interface::calc_screen_point(native_window_type wd, nana::point& pos) + { +#if defined(NANA_WINDOWS) + POINT point = {pos.x, pos.y}; + if(::ClientToScreen(reinterpret_cast(wd), &point)) + { + pos.x = point.x; + pos.y = point.y; + return true; + } + return false; +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + int x = pos.x, y = pos.y; + Window child; + return (True == ::XTranslateCoordinates(restrict::spec.open_display(), + reinterpret_cast(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child)); +#endif + } + + bool native_interface::calc_window_point(native_window_type wd, nana::point& pos) + { +#if defined(NANA_WINDOWS) + POINT point = {pos.x, pos.y}; + if(::ScreenToClient(reinterpret_cast(wd), &point)) + { + pos.x = point.x; + pos.y = point.y; + return true; + } + return false; +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + int x = pos.x, y = pos.y; + Window child; + return (True == ::XTranslateCoordinates(restrict::spec.open_display(), + restrict::spec.root_window(), reinterpret_cast(wd), x, y, &pos.x, &pos.y, &child)); +#endif + } + + native_window_type native_interface::find_window(int x, int y) + { +#if defined(NANA_WINDOWS) + POINT pos = {x, y}; + return reinterpret_cast(::WindowFromPoint(pos)); +#elif defined(NANA_X11) + nana::detail::platform_scope_guard psg; + + Window root = restrict::spec.root_window(); + Window wd = root; + Window child = 0; + int dropx = 0, dropy = 0; + while(True == ::XTranslateCoordinates(restrict::spec.open_display(), root, wd, x, y, &dropx, &dropy, &child)) + { + if(0 == child) break; + wd = child; + } + return reinterpret_cast(wd); +#endif + } + + nana::size native_interface::check_track_size(nana::size sz, unsigned ext_width, unsigned ext_height, bool true_for_max) + { +#if defined(NANA_WINDOWS) + int x; + int y; + if(true_for_max) + { + x = ::GetSystemMetrics(SM_CXMAXTRACK); + y = ::GetSystemMetrics(SM_CYMAXTRACK); + if(static_cast(x) < sz.width + ext_width) + sz.width = static_cast(x); + if(static_cast(y) < sz.height + ext_height) + sz.height = static_cast(y); + } + else + { + x = ::GetSystemMetrics(SM_CXMINTRACK); + y = ::GetSystemMetrics(SM_CYMINTRACK); + if(static_cast(x) > sz.width + ext_width) + sz.width = static_cast(x); + if(static_cast(y) > sz.height + ext_height) + sz.height = static_cast(y); + } +#endif + return sz; + } + //end struct native_interface + }//end namespace detail +}//end namespace nana diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp new file mode 100644 index 00000000..4d02ccea --- /dev/null +++ b/source/gui/detail/win32/bedrock.cpp @@ -0,0 +1,1801 @@ +/* + * A Bedrock Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/win32/bedrock.cpp + */ + +#include + +#include PLATFORM_SPEC_HPP +#include GUI_BEDROCK_HPP +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif + +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif + +typedef void (CALLBACK *win_event_proc_t)(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime); + +namespace nana +{ + void notifications_window_proc(HWND wd, WPARAM wparam, LPARAM lparam); //Defined in notifier.cpp + + //class internal_scope_guard + internal_scope_guard::internal_scope_guard() + { + detail::bedrock::instance().wd_manager.internal_lock().lock(); + } + internal_scope_guard::~internal_scope_guard() + { + detail::bedrock::instance().wd_manager.internal_lock().unlock(); + } + //end class internal_scope_guard +namespace detail +{ + namespace restrict + { + typedef struct tagTRACKMOUSEEVENT{ + unsigned long cbSize; + unsigned long dwFlags; + void* hwndTrack; + unsigned long dwHoverTime; + } TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT; + + typedef int (__stdcall* track_mouse_event_type)(LPTRACKMOUSEEVENT); + + int __stdcall dummy_track_mouse_event(LPTRACKMOUSEEVENT) + { + return 1; + } + + track_mouse_event_type track_mouse_event; + + typedef HIMC (__stdcall * imm_get_context_type)(HWND); + imm_get_context_type imm_get_context; + + typedef BOOL (__stdcall* imm_release_context_type)(HWND, HIMC); + imm_release_context_type imm_release_context; + + typedef BOOL (__stdcall* imm_set_composition_font_type)(HIMC, LOGFONTW*); + imm_set_composition_font_type imm_set_composition_font; + + typedef BOOL (__stdcall* imm_set_composition_window_type)(HIMC, LPCOMPOSITIONFORM); + imm_set_composition_window_type imm_set_composition_window; + } +#pragma pack(1) + //Decoder of WPARAM and LPARAM + struct wparam_button + { + bool left:1; + bool right:1; + bool shift:1; + bool ctrl:1; + bool middle:1; + bool place_holder:3; + char place_holder_c[1]; + short wheel_delta; + }; + + template + struct param_mouse + { + wparam_button button; + short x; + short y; + }; + + template<> + struct param_mouse<8> + { + wparam_button button; + char _x64_placeholder[4]; + short x; + short y; + }; + + template + struct param_size + { + unsigned long state; + short width; + short height; + }; + + template<> + struct param_size<8> + { + unsigned long state; + char _x64_placeholder[4]; + short width; + short height; + }; + + union parameter_decoder + { + struct + { + WPARAM wparam; + LPARAM lparam; + }raw_param; + + param_mouse mouse; + param_size size; + }; +#pragma pack() + + struct bedrock::thread_context + { + unsigned event_pump_ref_count{0}; + int window_count{0}; //The number of windows + core_window_t* event_window{nullptr}; + + struct platform_detail_tag + { + nana::char_t keychar; + }platform; + + struct cursor_tag + { + core_window_t * window; + native_window_type native_handle; + nana::cursor predef_cursor; + HCURSOR handle; + }cursor; + + thread_context() + { + cursor.window = nullptr; + cursor.native_handle = nullptr; + cursor.predef_cursor = nana::cursor::arrow; + cursor.handle = nullptr; + } + }; + + struct bedrock::private_impl + { + typedef std::map thr_context_container; + std::recursive_mutex mutex; + thr_context_container thr_contexts; + + element_store estore; + + struct cache_type + { + struct thread_context_cache + { + unsigned tid = 0; + thread_context *object = nullptr; + }tcontext; + }cache; + + struct menu_tag + { + core_window_t* taken_window = nullptr; + native_window_type window = nullptr; + native_window_type owner = nullptr; + bool has_keyboard = false; + }menu; + + struct keyboard_tracking_state_tag + { + keyboard_tracking_state_tag() + :alt(0) + {} + + bool has_shortkey_occured = false; + bool has_keyup = true; + unsigned long alt : 2; + }keyboard_tracking_state; + }; + + //class bedrock defines a static object itself to implement a static singleton + //here is the definition of this object + bedrock bedrock::bedrock_object; + + static LRESULT WINAPI Bedrock_WIN32_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + + bedrock::bedrock() + :impl_(new private_impl) + { + nana::detail::platform_spec::instance(); //to guaranty the platform_spec object is initialized before using. + + + WNDCLASSEX wincl; + wincl.hInstance = ::GetModuleHandle(0); + wincl.lpszClassName = STR("NanaWindowInternal"); + wincl.lpfnWndProc = &Bedrock_WIN32_WindowProc; + wincl.style = CS_DBLCLKS | CS_OWNDC; + wincl.cbSize = sizeof(wincl); + wincl.hIcon = ::LoadIcon (0, IDI_APPLICATION); + wincl.hIconSm = wincl.hIcon; + wincl.hCursor = ::LoadCursor (0, IDC_ARROW); + wincl.lpszMenuName = 0; + wincl.cbClsExtra = 0; + wincl.cbWndExtra = 0; + wincl.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + + ::RegisterClassEx(&wincl); + + restrict::track_mouse_event = (restrict::track_mouse_event_type)::GetProcAddress(::GetModuleHandleA("User32.DLL"), "TrackMouseEvent"); + + if(!restrict::track_mouse_event) + restrict::track_mouse_event = restrict::dummy_track_mouse_event; + + HMODULE imm32 = ::GetModuleHandleA("Imm32.DLL"); + restrict::imm_get_context = reinterpret_cast( + ::GetProcAddress(imm32, "ImmGetContext")); + + restrict::imm_release_context = reinterpret_cast( + ::GetProcAddress(imm32, "ImmReleaseContext")); + + restrict::imm_set_composition_font = reinterpret_cast( + ::GetProcAddress(imm32, "ImmSetCompositionFontW")); + + restrict::imm_set_composition_window = reinterpret_cast( + ::GetProcAddress(imm32, "ImmSetCompositionWindow")); + } + + bedrock::~bedrock() + { + if(wd_manager.number_of_core_window()) + { + std::stringstream ss; + ss<<"Nana.GUI detects a memory leaks in window_manager, "<(wd_manager.number_of_core_window())<<" window(s) are not uninstalled."; + ::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK); + } + + if(evt_operation.size()) + { + std::stringstream ss; + ss<<"Nana.GUI detects a memory leaks in events operation, "<(evt_operation.size())<<" event(s) are not uninstalled."; + ::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK); + } + delete impl_; + } + + //inc_window + //@brief: increament the number of windows + int bedrock::inc_window(unsigned tid) + { + //impl refers to the object of private_impl, the object is created when bedrock is creating. + private_impl * impl = instance().impl_; + std::lock_guardmutex)> lock(impl->mutex); + + int & cnt = (impl->thr_contexts[tid ? tid : nana::system::this_thread_id()].window_count); + return (cnt < 0 ? cnt = 1 : ++cnt); + } + + auto bedrock::open_thread_context(unsigned tid) -> thread_context* + { + if(0 == tid) tid = nana::system::this_thread_id(); + std::lock_guardmutex)> lock(impl_->mutex); + if(impl_->cache.tcontext.tid == tid) + return impl_->cache.tcontext.object; + + impl_->cache.tcontext.tid = tid; + auto i = impl_->thr_contexts.find(tid); + thread_context * context = (i == impl_->thr_contexts.end() ? &(impl_->thr_contexts[tid]) : &(i->second)); + impl_->cache.tcontext.object = context; + return context; + } + + auto bedrock::get_thread_context(unsigned tid) -> thread_context * + { + if(0 == tid) tid = nana::system::this_thread_id(); + + std::lock_guardmutex)> lock(impl_->mutex); + auto & cachectx = impl_->cache.tcontext; + if(cachectx.tid == tid) + return cachectx.object; + + auto i = impl_->thr_contexts.find(tid); + if(i != impl_->thr_contexts.end()) + { + cachectx.tid = tid; + return (cachectx.object = &(i->second)); + } + + cachectx.tid = 0; + return nullptr; + } + + void bedrock::remove_thread_context(unsigned tid) + { + if(0 == tid) tid = nana::system::this_thread_id(); + + std::lock_guardmutex)> lock(impl_->mutex); + + if(impl_->cache.tcontext.tid == tid) + { + impl_->cache.tcontext.tid = 0; + impl_->cache.tcontext.object = nullptr; + } + + impl_->thr_contexts.erase(tid); + } + + bedrock& bedrock::instance() + { + return bedrock_object; + } + + void bedrock::map_thread_root_buffer(core_window_t* wd) + { + ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), 0); + } + + void interior_helper_for_menu(MSG& msg, native_window_type menu_window) + { + switch(msg.message) + { + case WM_KEYDOWN: + case WM_CHAR: + case WM_KEYUP: + msg.hwnd = reinterpret_cast(menu_window); + break; + } + } + + void bedrock::pump_event(window modal_window, bool is_modal) + { + const unsigned tid = ::GetCurrentThreadId(); + thread_context * context = this->open_thread_context(tid); + if(0 == context->window_count) + { + //test if there is not a window + //GetMessage may block if there is not a window + remove_thread_context(); + return; + } + + ++(context->event_pump_ref_count); + + auto & intr_locker = wd_manager.internal_lock(); + intr_locker.revert(); + + try + { + MSG msg; + if(modal_window) + { + HWND native_handle = reinterpret_cast( + root(reinterpret_cast(modal_window))); + if (is_modal) + { + HWND owner = ::GetWindow(native_handle, GW_OWNER); + if (owner && owner != ::GetDesktopWindow()) + ::EnableWindow(owner, false); + + + while (::IsWindow(native_handle)) + { + ::WaitMessage(); + while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) break; + + if ((msg.message == WM_CHAR || msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) || !::IsDialogMessage(native_handle, &msg)) + { + auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); + if (menu_wd) interior_helper_for_menu(msg, menu_wd); + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + + wd_manager.remove_trash_handle(tid); + } + } + } + } + else + { + while (::IsWindow(native_handle)) + { + if (-1 != ::GetMessage(&msg, 0, 0, 0)) + { + auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); + if (menu_wd) interior_helper_for_menu(msg, menu_wd); + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + wd_manager.remove_trash_handle(tid); + if (msg.message == WM_DESTROY && msg.hwnd == native_handle) + break; + }//end while + } + } + else + { + while(context->window_count) + { + if(-1 != ::GetMessage(&msg, 0, 0, 0)) + { + auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); + if(menu_wd) interior_helper_for_menu(msg, menu_wd); + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + wd_manager.remove_trash_handle(tid); + }//end while + + //Empty these rest messages, there is not a window to process these messages. + while(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)); + } + } + catch(std::exception& e) + { + (msgbox(modal_window, STR("An uncaptured std::exception during message pumping: ")).icon(msgbox::icon_information) + <event_pump_ref_count)) + { + if ((nullptr == modal_window) || (0 == context->window_count)) + remove_thread_context(); + } + throw; + } + catch(...) + { + (msgbox(modal_window, STR("An exception during message pumping!")).icon(msgbox::icon_information) + << STR("An uncaptured non-std exception during message pumping!") + ).show(); + internal_scope_guard lock; + _m_except_handler(); + + intr_locker.forward(); + if(0 == --(context->event_pump_ref_count)) + { + if((nullptr == modal_window) || (0 == context->window_count)) + remove_thread_context(); + } + throw; + } + + intr_locker.forward(); + if(0 == --(context->event_pump_ref_count)) + { + if((nullptr == modal_window) || (0 == context->window_count)) + remove_thread_context(); + } + }//end pump_event + + void assign_arg(nana::arg_mouse& arg, basic_window* wd, unsigned msg, const parameter_decoder& pmdec) + { + arg.window_handle = reinterpret_cast(wd); + //event code + switch (msg) + { + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: + arg.evt_code = event_code::mouse_up; + break; + case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: + arg.evt_code = (wd->flags.dbl_click ? event_code::dbl_click : event_code::mouse_down); + break; + case WM_MOUSEMOVE: + arg.evt_code = event_code::mouse_move; + break; + } + + //event arguments + switch (msg) + { + case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: + arg.evt_code = event_code::mouse_down; + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: + case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: + case WM_MOUSEMOVE: + arg.pos.x = pmdec.mouse.x - wd->pos_root.x; + arg.pos.y = pmdec.mouse.y - wd->pos_root.y; + arg.shift = pmdec.mouse.button.shift; + arg.ctrl = pmdec.mouse.button.ctrl; + + switch (msg) + { + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: + arg.left_button = (WM_LBUTTONUP == msg); + arg.right_button = (WM_RBUTTONUP == msg); + arg.mid_button = (WM_MBUTTONUP == msg); + break; + default: + arg.left_button = pmdec.mouse.button.left; + arg.mid_button = pmdec.mouse.button.middle; + arg.right_button = pmdec.mouse.button.right; + } + break; + } + } + + void assign_arg(arg_focus& arg, basic_window* wd, native_window_type recv, bool getting) + { + arg.window_handle = reinterpret_cast(wd); + arg.receiver = recv; + arg.getting = getting; + } + + void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec) + { + arg.window_handle = reinterpret_cast(wd); + arg.evt_code = event_code::mouse_wheel; + + POINT point = { pmdec.mouse.x, pmdec.mouse.y }; + ::ScreenToClient(reinterpret_cast(wd->root), &point); + + arg.upwards = (pmdec.mouse.button.wheel_delta >= 0); + arg.distance = std::abs(pmdec.mouse.button.wheel_delta); + + arg.pos.x = static_cast(point.x) - wd->pos_root.x; + arg.pos.y = static_cast(point.y) - wd->pos_root.y; + arg.left_button = pmdec.mouse.button.left; + arg.mid_button = pmdec.mouse.button.middle; + arg.right_button = pmdec.mouse.button.right; + arg.ctrl = pmdec.mouse.button.ctrl; + arg.shift = pmdec.mouse.button.shift; + } + + //trivial_message + // The Windows messaging always sends a message to the window thread queue when the calling is in other thread. + //If messages can be finished without expecting Nana's window manager, the trivail_message function would + //handle those messages. This is a method to avoid a deadlock, that calling waits for the handling and they require + //Nana's window manager. + bool trivial_message(HWND wd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT & ret) + { + bedrock & bedrock = bedrock::instance(); + switch(msg) + { + case nana::detail::messages::async_activate: + ::EnableWindow(wd, true); + ::SetActiveWindow(wd); + return true; + case nana::detail::messages::async_set_focus: + ::SetFocus(wd); + return true; + case nana::detail::messages::operate_caret: + //Refer to basis.hpp for this specification. + switch(wParam) + { + case 1: //Delete + ::DestroyCaret(); + break; + case 2: //SetPos + ::SetCaretPos(reinterpret_cast(lParam)->x, reinterpret_cast(lParam)->y); + delete reinterpret_cast(lParam); + break; + } + return true; + case nana::detail::messages::map_thread_root_buffer: + bedrock.wd_manager.map(reinterpret_cast(wParam)); + ::UpdateWindow(wd); + return true; + case nana::detail::messages::remote_thread_move_window: + { + auto * mw = reinterpret_cast(wParam); + + ::RECT r; + ::GetWindowRect(wd, &r); + if(mw->ignore & mw->Pos) + { + mw->x = r.left; + mw->y = r.top; + } + else + { + HWND owner = ::GetWindow(wd, GW_OWNER); + if(owner) + { + ::RECT owr; + ::GetWindowRect(owner, &owr); + ::POINT pos = {owr.left, owr.top}; + ::ScreenToClient(owner, &pos); + mw->x += (owr.left - pos.x); + mw->y += (owr.top - pos.y); + } + } + + if(mw->ignore & mw->Size) + { + mw->width = r.right - r.left; + mw->height = r.bottom - r.top; + } + ::MoveWindow(wd, mw->x, mw->y, mw->width, mw->height, true); + delete mw; + } + return true; + case nana::detail::messages::remote_thread_set_window_pos: + ::SetWindowPos(wd, reinterpret_cast(wParam), 0, 0, 0, 0, static_cast(lParam)); + return true; + case nana::detail::messages::remote_thread_set_window_text: + ::SetWindowTextW(wd, reinterpret_cast(wParam)); + delete [] reinterpret_cast(wParam); + return true; + case nana::detail::messages::remote_thread_destroy_window: + detail::native_interface::close_window(reinterpret_cast(wd)); //The owner would be actived before the message has posted in current thread. + { + internal_scope_guard sg; + auto * thrd = bedrock.get_thread_context(); + if(thrd && (thrd->window_count == 0)) + ::PostQuitMessage(0); + } + ret = ::DefWindowProc(wd, msg, wParam, lParam); + return true; + case nana::detail::messages::tray: + notifications_window_proc(wd, wParam, lParam); + return true; + default: + break; + } + + switch(msg) + { + case WM_DESTROY: + case WM_SHOWWINDOW: + case WM_SIZING: + case WM_MOVE: + case WM_SIZE: + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_PAINT: + case WM_CLOSE: + case WM_MOUSEACTIVATE: + case WM_GETMINMAXINFO: + case WM_WINDOWPOSCHANGED: + case WM_NCDESTROY: + case WM_NCLBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_IME_STARTCOMPOSITION: + case WM_DROPFILES: + case WM_MOUSELEAVE: + case WM_MOUSEWHEEL: //The WM_MOUSELAST may not include the WM_MOUSEWHEEL/WM_MOUSEHWHEEL when the version of SDK is low. + case WM_MOUSEHWHEEL: + return false; + default: + if((WM_MOUSEFIRST <= msg && msg <= WM_MOUSELAST) || (WM_KEYFIRST <= msg && msg <= WM_KEYLAST)) + return false; + } + + ret = ::DefWindowProc(wd, msg, wParam, lParam); + return true; + } + + void adjust_sizing(bedrock::core_window_t* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height) + { + unsigned width = static_cast(r->right - r->left) - wd->extra_width; + unsigned height = static_cast(r->bottom - r->top) - wd->extra_height; + + if(wd->max_track_size.width && (wd->max_track_size.width < req_width)) + req_width = wd->max_track_size.width; + else if(wd->min_track_size.width && (wd->min_track_size.width > req_width)) + req_width = wd->min_track_size.width; + + if(wd->max_track_size.height && (wd->max_track_size.height < req_height)) + req_height = wd->max_track_size.height; + else if(wd->min_track_size.height && (wd->min_track_size.height > req_height)) + req_height = wd->min_track_size.height; + + if(req_width != width) + { + switch(edge) + { + case WMSZ_LEFT: + case WMSZ_BOTTOMLEFT: + case WMSZ_TOPLEFT: + r->left = r->right - static_cast(req_width) - wd->extra_width; + break; + case WMSZ_RIGHT: + case WMSZ_BOTTOMRIGHT: + case WMSZ_TOPRIGHT: + case WMSZ_TOP: + case WMSZ_BOTTOM: + r->right = r->left + static_cast(req_width) + wd->extra_width; + break; + } + } + + if(req_height != height) + { + switch(edge) + { + case WMSZ_TOP: + case WMSZ_TOPLEFT: + case WMSZ_TOPRIGHT: + r->top = r->bottom - static_cast(req_height) - wd->extra_height; + break; + case WMSZ_BOTTOM: + case WMSZ_BOTTOMLEFT: + case WMSZ_BOTTOMRIGHT: + case WMSZ_LEFT: + case WMSZ_RIGHT: + r->bottom = r->top + static_cast(req_height) + wd->extra_height; + break; + } + } + } + + template + void emit_drawer(void (::nana::detail::drawer::*event_ptr)(const Arg&), basic_window* wd, const Arg& arg, bedrock::thread_context* thrd) + { + if (bedrock::instance().wd_manager.available(wd) == false) + return; + + basic_window* prev_event_wd; + if (thrd) + { + prev_event_wd = thrd->event_window; + thrd->event_window = wd; + } + + if (wd->other.upd_state == basic_window::update_state::none) + wd->other.upd_state = basic_window::update_state::lazy; + + (wd->drawer.*event_ptr)(arg); + + if (thrd) thrd->event_window = prev_event_wd; + } + + LRESULT CALLBACK Bedrock_WIN32_WindowProc(HWND root_window, UINT message, WPARAM wParam, LPARAM lParam) + { + LRESULT window_proc_value = 0; + if(trivial_message(root_window, message, wParam, lParam, window_proc_value)) + return window_proc_value; + + static auto& brock = bedrock::instance(); + static restrict::TRACKMOUSEEVENT track = {sizeof track, 0x00000002}; + + auto native_window = reinterpret_cast(root_window); + auto* root_runtime = brock.wd_manager.root_runtime(native_window); + + if(root_runtime) + { + bool def_window_proc = false; + auto& context = *brock.get_thread_context(); + + auto pressed_wd = root_runtime->condition.pressed; + auto hovered_wd = root_runtime->condition.hovered; + + parameter_decoder pmdec; + pmdec.raw_param.lparam = lParam; + pmdec.raw_param.wparam = wParam; + + internal_scope_guard lock; + auto msgwnd = root_runtime->window; + + switch(message) + { + case WM_IME_STARTCOMPOSITION: + if(msgwnd->other.attribute.root->ime_enabled) + { + auto native_font = msgwnd->drawer.graphics.typeface().handle(); + LOGFONTW logfont; + ::GetObjectW(reinterpret_cast(native_font), sizeof logfont, &logfont); + + HIMC imc = restrict::imm_get_context(root_window); + restrict::imm_set_composition_font(imc, &logfont); + + POINT pos; + ::GetCaretPos(&pos); + + COMPOSITIONFORM cf = {CFS_POINT}; + cf.ptCurrentPos = pos; + restrict::imm_set_composition_window(imc, &cf); + restrict::imm_release_context(root_window, imc); + } + def_window_proc = true; + break; + case WM_GETMINMAXINFO: + { + bool take_over = false; + auto mmi = reinterpret_cast(lParam); + + if(msgwnd->min_track_size.width && msgwnd->min_track_size.height) + { + mmi->ptMinTrackSize.x = static_cast(msgwnd->min_track_size.width + msgwnd->extra_width); + mmi->ptMinTrackSize.y = static_cast(msgwnd->min_track_size.height + msgwnd->extra_height); + take_over = true; + } + + if(false == msgwnd->flags.fullscreen) + { + if(msgwnd->max_track_size.width && msgwnd->max_track_size.height) + { + mmi->ptMaxTrackSize.x = static_cast(msgwnd->max_track_size.width + msgwnd->extra_width); + mmi->ptMaxTrackSize.y = static_cast(msgwnd->max_track_size.height + msgwnd->extra_height); + if(mmi->ptMaxSize.x > mmi->ptMaxTrackSize.x) + mmi->ptMaxSize.x = mmi->ptMaxTrackSize.x; + if(mmi->ptMaxSize.y > mmi->ptMaxTrackSize.y) + mmi->ptMaxSize.y = mmi->ptMaxTrackSize.y; + + take_over = true; + } + } + + if (take_over) + return 0; + } + break; + case WM_SHOWWINDOW: + if (msgwnd->visible && (wParam == FALSE)) + brock.event_expose(msgwnd, false); + else if ((!msgwnd->visible) && (wParam != FALSE)) + brock.event_expose(msgwnd, true); + def_window_proc = true; + break; + case WM_WINDOWPOSCHANGED: + if ((reinterpret_cast(lParam)->flags & SWP_SHOWWINDOW) && (!msgwnd->visible)) + brock.event_expose(msgwnd, true); + else if((reinterpret_cast(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible) + brock.event_expose(msgwnd, false); + + def_window_proc = true; + break; + case WM_SETFOCUS: + if(msgwnd->flags.enabled && msgwnd->flags.take_active) + { + auto focus = msgwnd->other.attribute.root->focus; + + if(focus && focus->together.caret) + focus->together.caret->set_active(true); + + msgwnd->root_widget->other.attribute.root->context.focus_changed = true; + + arg_focus arg; + assign_arg(arg, focus, native_window, true); + if (!brock.emit(event_code::focus, focus, arg, true, &context)) + brock.wd_manager.set_focus(msgwnd, true); + } + break; + case WM_KILLFOCUS: + if(msgwnd->other.attribute.root->focus) + { + auto focus = msgwnd->other.attribute.root->focus; + + arg_focus arg; + assign_arg(arg, focus, reinterpret_cast(wParam), false); + if(brock.emit(event_code::focus, focus, arg, true, &context)) + { + if(focus->together.caret) + focus->together.caret->set_active(false); + } + + //wParam indicates a handle of window that receives the focus. + brock.close_menu_if_focus_other_window(reinterpret_cast(wParam)); + } + //focus_changed means that during an event procedure if the focus is changed + if(brock.wd_manager.available(msgwnd)) + msgwnd->root_widget->other.attribute.root->context.focus_changed = true; + break; + case WM_MOUSEACTIVATE: + if(msgwnd->flags.take_active == false) + return MA_NOACTIVATE; + break; + case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: + pressed_wd = nullptr; + msgwnd = brock.wd_manager.find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); + if(msgwnd && msgwnd->flags.enabled) + { + if(msgwnd->flags.take_active) + brock.wd_manager.set_focus(msgwnd, false); + + arg_mouse arg; + assign_arg(arg, msgwnd, message, pmdec); + if (brock.emit(arg.evt_code, msgwnd, arg, true, &context)) + { + if (brock.wd_manager.available(msgwnd)) + pressed_wd = msgwnd; + } + } + break; + case WM_NCLBUTTONDOWN: case WM_NCMBUTTONDOWN: case WM_NCRBUTTONDOWN: + brock.close_menu_if_focus_other_window(native_window); + def_window_proc = true; + break; + case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: + msgwnd = brock.wd_manager.find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); + if(nullptr == msgwnd) break; + + //if event on the menubar, just remove the menu if it is not associating with the menubar + if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) + brock.remove_menu(); + else + brock.close_menu_if_focus_other_window(msgwnd->root); + + if(msgwnd->flags.enabled) + { + pressed_wd = msgwnd; + auto new_focus = (msgwnd->flags.take_active ? msgwnd : msgwnd->other.active_window); + if(new_focus) + { + auto kill_focus = brock.wd_manager.set_focus(new_focus, false); + if(kill_focus != new_focus) + { + brock.wd_manager.do_lazy_refresh(kill_focus, false); + msgwnd->root_widget->other.attribute.root->context.focus_changed = false; + } + } + + arg_mouse arg; + assign_arg(arg, msgwnd, message, pmdec); + msgwnd->flags.action = mouse_action::pressed; + if (brock.emit(event_code::mouse_down, msgwnd, arg, true, &context)) + { + //If a root_window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. + if(msgwnd->root_widget->other.attribute.root->context.focus_changed) + { + auto pos = native_interface::cursor_position(); + auto rootwd = native_interface::find_window(pos.x, pos.y); + native_interface::calc_window_point(rootwd, pos); + if(msgwnd != brock.wd_manager.find_window(rootwd, pos.x, pos.y)) + { + //call the drawer mouse up event for restoring the surface graphics + msgwnd->flags.action = mouse_action::normal; + + arg.evt_code = event_code::mouse_up; + emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); + brock.wd_manager.do_lazy_refresh(msgwnd, false); + } + } + } + else + pressed_wd = nullptr; + } + break; + //mouse_click, mouse_up + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + msgwnd = brock.wd_manager.find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); + if(nullptr == msgwnd) + break; + + msgwnd->flags.action = mouse_action::normal; + if(msgwnd->flags.enabled) + { + nana::arg_mouse arg; + assign_arg(arg, msgwnd, message, pmdec); + + const bool hit = msgwnd->dimension.is_hit(arg.pos); + + bool fire_click = false; + if(msgwnd == pressed_wd) + { + if(msgwnd->flags.enabled && hit) + { + msgwnd->flags.action = mouse_action::over; + arg.evt_code = event_code::click; + emit_drawer(&drawer::click, msgwnd, arg, &context); + fire_click = true; + } + } + + //Do mouse_up, this handle may be closed by click handler. + if(brock.wd_manager.available(msgwnd) && msgwnd->flags.enabled) + { + if(hit) + msgwnd->flags.action = mouse_action::over; + + arg.evt_code = event_code::mouse_up; + emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); + + auto evt_ptr = msgwnd->together.events_ptr; + + if (fire_click) + { + arg.evt_code = event_code::click; + msgwnd->together.attached_events->click.emit(arg); + } + + if (brock.wd_manager.available(msgwnd)) + { + arg.evt_code = event_code::mouse_up; + msgwnd->together.attached_events->mouse_up.emit(arg); + } + } + else if (fire_click) + { + arg.evt_code = event_code::click; + msgwnd->together.attached_events->click.emit(arg); + } + brock.wd_manager.do_lazy_refresh(msgwnd, false); + } + pressed_wd = nullptr; + break; + case WM_MOUSEMOVE: + msgwnd = brock.wd_manager.find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); + if (brock.wd_manager.available(hovered_wd) && (msgwnd != hovered_wd)) + { + brock.event_msleave(hovered_wd); + hovered_wd->flags.action = mouse_action::normal; + hovered_wd = nullptr; + + //if msgwnd is neither captured window nor the child of captured window, + //redirect the msgwnd to the captured window. + auto wd = brock.wd_manager.capture_redirect(msgwnd); + if(wd) + msgwnd = wd; + } + + else if(msgwnd) + { + bool prev_captured_inside; + if(brock.wd_manager.capture_window_entered(pmdec.mouse.x, pmdec.mouse.y, prev_captured_inside)) + { + event_code evt_code; + if(prev_captured_inside) + { + evt_code = event_code::mouse_leave; + msgwnd->flags.action = mouse_action::normal; + } + else + { + evt_code = event_code::mouse_enter; + msgwnd->flags.action = mouse_action::over; + } + arg_mouse arg; + assign_arg(arg, msgwnd, message, pmdec); + arg.evt_code = evt_code; + brock.emit(evt_code, msgwnd, arg, true, &context); + } + } + + if(msgwnd) + { + arg_mouse arg; + assign_arg(arg, msgwnd, message, pmdec); + msgwnd->flags.action = mouse_action::over; + if (hovered_wd != msgwnd) + { + hovered_wd = msgwnd; + arg.evt_code = event_code::mouse_enter; + brock.emit(event_code::mouse_enter, msgwnd, arg, true, &context); + } + + arg.evt_code = event_code::mouse_move; + brock.emit(event_code::mouse_move, msgwnd, arg, true, &context); + track.hwndTrack = native_window; + restrict::track_mouse_event(&track); + } + if (!brock.wd_manager.available(hovered_wd)) + hovered_wd = nullptr; + break; + case WM_MOUSELEAVE: + brock.event_msleave(hovered_wd); + hovered_wd = nullptr; + break; + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + { + //The focus window receives the message in Windows system, it should be redirected to the hovered window + ::POINT scr_pos{ int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position + auto pointer_wd = ::WindowFromPoint(scr_pos); + if (pointer_wd == root_window) + { + ::ScreenToClient(pointer_wd, &scr_pos); + auto scrolled_wd = brock.wd_manager.find_window(reinterpret_cast(pointer_wd), scr_pos.x, scr_pos.y); + + def_window_proc = true; + while (scrolled_wd) + { + if (scrolled_wd->together.attached_events->mouse_wheel.length() != 0) + { + def_window_proc = false; + nana::point mspos{ scr_pos.x, scr_pos.y }; + brock.wd_manager.calc_window_point(scrolled_wd, mspos); + + arg_wheel arg; + arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); + assign_arg(arg, scrolled_wd, pmdec); + brock.emit(event_code::mouse_wheel, scrolled_wd, arg, true, &context); + break; + } + scrolled_wd = scrolled_wd->parent; + } + } + else + { + DWORD pid = 0; + ::GetWindowThreadProcessId(pointer_wd, &pid); + if (pid == ::GetCurrentProcessId()) + ::PostMessage(pointer_wd, message, wParam, lParam); + } + } + break; + case WM_DROPFILES: + { + HDROP drop = reinterpret_cast(wParam); + POINT pos; + ::DragQueryPoint(drop, &pos); + + msgwnd = brock.wd_manager.find_window(native_window, pos.x, pos.y); + if(msgwnd) + { + arg_dropfiles dropfiles; + + std::unique_ptr varbuf; + std::size_t bufsize = 0; + + unsigned size = ::DragQueryFile(drop, 0xFFFFFFFF, 0, 0); + for(unsigned i = 0; i < size; ++i) + { + unsigned reqlen = ::DragQueryFile(drop, i, 0, 0) + 1; + if(bufsize < reqlen) + { + varbuf.reset(new nana::char_t[reqlen]); + bufsize = reqlen; + } + + ::DragQueryFile(drop, i, varbuf.get(), reqlen); + dropfiles.files.emplace_back(varbuf.get()); + } + + while(msgwnd && (msgwnd->flags.dropable == false)) + msgwnd = msgwnd->parent; + + if(msgwnd) + { + dropfiles.pos.x = pos.x; + dropfiles.pos.y = pos.y; + + brock.wd_manager.calc_window_point(msgwnd, dropfiles.pos); + dropfiles.window_handle = reinterpret_cast(msgwnd); + + msgwnd->together.attached_events->mouse_dropfiles.emit(dropfiles); + brock.wd_manager.do_lazy_refresh(msgwnd, false); + } + } + + ::DragFinish(drop); + } + break; + case WM_SIZING: + { + ::RECT* const r = reinterpret_cast(lParam); + unsigned width = static_cast(r->right - r->left) - msgwnd->extra_width; + unsigned height = static_cast(r->bottom - r->top) - msgwnd->extra_height; + + if(msgwnd->max_track_size.width || msgwnd->min_track_size.width) + { + if(wParam == WMSZ_LEFT || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_TOPLEFT) + { + if(msgwnd->max_track_size.width && (width > msgwnd->max_track_size.width)) + r->left = r->right - static_cast(msgwnd->max_track_size.width) - msgwnd->extra_width; + if(msgwnd->min_track_size.width && (width < msgwnd->min_track_size.width)) + r->left = r->right - static_cast(msgwnd->min_track_size.width) - msgwnd->extra_width; + } + else if(wParam == WMSZ_RIGHT || wParam == WMSZ_BOTTOMRIGHT || wParam == WMSZ_TOPRIGHT) + { + if(msgwnd->max_track_size.width && (width > msgwnd->max_track_size.width)) + r->right = r->left + static_cast(msgwnd->max_track_size.width) + msgwnd->extra_width; + if(msgwnd->min_track_size.width && (width < msgwnd->min_track_size.width)) + r->right = r->left + static_cast(msgwnd->min_track_size.width) + msgwnd->extra_width; + } + } + + if(msgwnd->max_track_size.height || msgwnd->min_track_size.height) + { + if(wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT) + { + if(msgwnd->max_track_size.height && (height > msgwnd->max_track_size.height)) + r->top = r->bottom - static_cast(msgwnd->max_track_size.height) - msgwnd->extra_height; + if(msgwnd->min_track_size.height && (height < msgwnd->min_track_size.height)) + r->top = r->bottom - static_cast(msgwnd->min_track_size.height) - msgwnd->extra_height; + } + else if(wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT) + { + if(msgwnd->max_track_size.height && (height > msgwnd->max_track_size.height)) + r->bottom = r->top + static_cast(msgwnd->max_track_size.height) + msgwnd->extra_height; + if(msgwnd->min_track_size.height && (height < msgwnd->min_track_size.height)) + r->bottom = r->top + static_cast(msgwnd->min_track_size.height) + msgwnd->extra_height; + } + } + + nana::size size_before( static_cast(r->right - r->left - msgwnd->extra_width), + static_cast(r->bottom - r->top - msgwnd->extra_height)); + + arg_resizing arg; + arg.window_handle = reinterpret_cast(msgwnd); + arg.width = size_before.width; + arg.height = size_before.height; + + switch (wParam) + { + case WMSZ_LEFT: + arg.border = window_border::left; break; + case WMSZ_RIGHT: + arg.border = window_border::right; break; + case WMSZ_BOTTOM: + arg.border = window_border::bottom; break; + case WMSZ_BOTTOMLEFT: + arg.border = window_border::bottom_left; break; + case WMSZ_BOTTOMRIGHT: + arg.border = window_border::bottom_right; break; + case WMSZ_TOP: + arg.border = window_border::top; break; + case WMSZ_TOPLEFT: + arg.border = window_border::top_left; break; + case WMSZ_TOPRIGHT: + arg.border = window_border::top_right; break; + } + + brock.emit(event_code::resizing, msgwnd, arg, false, &context); + + if (arg.width != width || arg.height != height) + { + adjust_sizing(msgwnd, r, static_cast(wParam), arg.width, arg.height); + return TRUE; + } + } + break; + case WM_SIZE: + if(wParam != SIZE_MINIMIZED) + brock.wd_manager.size(msgwnd, size(pmdec.size.width, pmdec.size.height), true, true); + break; + case WM_MOVE: + brock.event_move(msgwnd, (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam)); + break; + case WM_PAINT: + { + ::PAINTSTRUCT ps; + ::HDC dc = ::BeginPaint(root_window, &ps); + + if((ps.rcPaint.left != ps.rcPaint.right) && (ps.rcPaint.bottom != ps.rcPaint.top)) + { + ::BitBlt(dc, + ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, + reinterpret_cast(msgwnd->root_graph->handle()->context), + ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); + } + ::EndPaint(root_window, &ps); + } + break; + case WM_SYSCHAR: + brock.set_keyboard_shortkey(true); + msgwnd = brock.wd_manager.find_shortkey(native_window, static_cast(wParam)); + if(msgwnd) + { + arg_keyboard arg; + arg.evt_code = event_code::shortkey; + arg.key = static_cast(wParam < 0x61 ? wParam + 0x61 - 0x41 : wParam); + arg.ctrl = arg.shift = false; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + brock.emit(event_code::shortkey, msgwnd, arg, true, &context); + } + break; + case WM_SYSKEYDOWN: + if(brock.whether_keyboard_shortkey() == false) + { + msgwnd = msgwnd->root_widget->other.attribute.root->menubar; + if(msgwnd) + { + brock.wd_manager.set_focus(msgwnd, false); + + arg_keyboard arg; + arg.evt_code = event_code::key_press; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = static_cast(wParam); + brock.get_key_state(arg); + brock.emit(event_code::key_press, msgwnd, arg, true, &context); + } + else if(brock.get_menu()) + brock.remove_menu(); + } + break; + case WM_SYSKEYUP: + if(brock.set_keyboard_shortkey(false) == false) + { + msgwnd = msgwnd->root_widget->other.attribute.root->menubar; + if(msgwnd) + { + arg_keyboard arg; + arg.evt_code = event_code::key_release; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = static_cast(wParam); + brock.get_key_state(arg); + brock.emit(event_code::key_release, msgwnd, arg, true, &context); + } + } + break; + case WM_KEYDOWN: + if(msgwnd->flags.enabled) + { + if(msgwnd->root != brock.get_menu()) + msgwnd = brock.focus(); + + if(msgwnd) + { + if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab + { + auto the_next = brock.wd_manager.tabstop(msgwnd, true); + if(the_next) + { + brock.wd_manager.set_focus(the_next, false); + brock.wd_manager.do_lazy_refresh(msgwnd, false); + brock.wd_manager.do_lazy_refresh(the_next, true); + root_runtime->condition.tabstop_focus_changed = true; + } + } + else + { + arg_keyboard arg; + arg.evt_code = event_code::key_press; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = static_cast(wParam); + brock.get_key_state(arg); + brock.emit(event_code::key_press, msgwnd, arg, true, &context); + } + } + } + break; + case WM_CHAR: + msgwnd = brock.focus(); + if(false == root_runtime->condition.tabstop_focus_changed) + { + if(msgwnd && msgwnd->flags.enabled) + { + arg_keyboard arg; + arg.evt_code = event_code::key_char; + arg.window_handle = reinterpret_cast(msgwnd); + arg.key = static_cast(wParam); + brock.get_key_state(arg); + arg.ignore = false; + + msgwnd->together.attached_events->key_char.emit(arg); + if ((false == arg.ignore) && brock.wd_manager.available(msgwnd)) + brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); + + brock.wd_manager.do_lazy_refresh(msgwnd, false); + } + } + else + root_runtime->condition.tabstop_focus_changed = false; + return 0; + case WM_KEYUP: + if(wParam != 18) //MUST NOT BE AN ALT + { + msgwnd = brock.focus(); + if(msgwnd) + { + arg_keyboard arg; + arg.evt_code = event_code::key_release; + arg.window_handle = reinterpret_cast(msgwnd); + arg.key = static_cast(wParam); + brock.get_key_state(arg); + arg.ignore = false; + brock.emit(event_code::key_release, msgwnd, arg, true, &context); + } + } + else + brock.set_keyboard_shortkey(false); + break; + case WM_CLOSE: + { + arg_unload arg; + arg.window_handle = reinterpret_cast(msgwnd); + arg.cancel = false; + brock.emit(event_code::unload, msgwnd, arg, true, &context); + if (!arg.cancel) + { + def_window_proc = true; + //Activate is owner, refer to the window_manager::close for the explaination + if (msgwnd->flags.modal || (msgwnd->owner == 0) || msgwnd->owner->flags.take_active) + native_interface::activate_owner(msgwnd->root); + } + break; + } + case WM_DESTROY: + if(msgwnd->root == brock.get_menu()) + brock.empty_menu(); + brock.wd_manager.destroy(msgwnd); + + nana::detail::platform_spec::instance().release_window_icon(msgwnd->root); + break; + case WM_NCDESTROY: + brock.rt_manager.remove_if_exists(msgwnd); + brock.wd_manager.destroy_handle(msgwnd); + + if(--context.window_count <= 0) + { + ::PostQuitMessage(0); + def_window_proc = true; + } + break; + default: + def_window_proc = true; + } + + root_runtime = brock.wd_manager.root_runtime(native_window); + if(root_runtime) + { + root_runtime->condition.pressed = pressed_wd; + root_runtime->condition.hovered = hovered_wd; + } + + if (!def_window_proc) + return 0; + } + + return ::DefWindowProc(root_window, message, wParam, lParam); + } + + nana::category::flags bedrock::category(core_window_t* wd) + { + if(wd) + { + internal_scope_guard isg; + if(wd_manager.available(wd)) + return wd->other.category; + } + return nana::category::flags::super; + } + + auto bedrock::focus() ->core_window_t* + { + core_window_t* wd = wd_manager.root(native_interface::get_focus_window()); + return (wd ? wd->other.attribute.root->focus : nullptr); + } + + native_window_type bedrock::root(core_window_t* wd) + { + if(wd) + { + internal_scope_guard isg; + if(wd_manager.available(wd)) + return wd->root; + } + return nullptr; + } + + void bedrock::set_menubar_taken(core_window_t* wd) + { + impl_->menu.taken_window = wd; + } + + bedrock::core_window_t* bedrock::get_menubar_taken() + { + core_window_t* wd = impl_->menu.taken_window; + impl_->menu.taken_window = nullptr; + return wd; + } + + bool bedrock::close_menu_if_focus_other_window(native_window_type wd) + { + if(impl_->menu.window && (impl_->menu.window != wd)) + { + wd = native_interface::get_owner_window(wd); + while(wd) + { + if(wd != impl_->menu.window) + wd = native_interface::get_owner_window(wd); + else + return false; + } + remove_menu(); + return true; + } + return false; + } + + void bedrock::set_menu(native_window_type menu_wd, bool has_keyboard) + { + if(menu_wd && impl_->menu.window != menu_wd) + { + remove_menu(); + + impl_->menu.window = menu_wd; + impl_->menu.owner = native_interface::get_owner_window(menu_wd); + impl_->menu.has_keyboard = has_keyboard; + } + } + + native_window_type bedrock::get_menu(native_window_type owner, bool is_keyboard_condition) + { + if( (impl_->menu.owner == nullptr) || + (owner && (impl_->menu.owner == owner)) + ) + { + return ((!is_keyboard_condition) || impl_->menu.has_keyboard ? impl_->menu.window : nullptr); + } + return nullptr; + } + + native_window_type bedrock::get_menu() + { + return impl_->menu.window; + } + + void bedrock::remove_menu() + { + if(impl_->menu.window) + { + auto delwin = impl_->menu.window; + impl_->menu.window = impl_->menu.owner = nullptr; + impl_->menu.has_keyboard = false; + native_interface::close_window(delwin); + } + } + + void bedrock::empty_menu() + { + if(impl_->menu.window) + { + impl_->menu.window = impl_->menu.owner = nullptr; + impl_->menu.has_keyboard = false; + } + } + + void bedrock::get_key_state(arg_keyboard& kb) + { + kb.ctrl = (0 != (::GetKeyState(VK_CONTROL) & 0x80)); + kb.shift = (0 != (::GetKeyState(VK_SHIFT) & 0x80)); + } + + bool bedrock::set_keyboard_shortkey(bool yes) + { + bool ret = impl_->keyboard_tracking_state.has_shortkey_occured; + impl_->keyboard_tracking_state.has_shortkey_occured = yes; + return ret; + } + + bool bedrock::whether_keyboard_shortkey() const + { + return impl_->keyboard_tracking_state.has_shortkey_occured; + } + + element_store& bedrock::get_element_store() const + { + return impl_->estore; + } + + bool bedrock::emit(event_code evt_code, core_window_t* wd, const arg_mouse& arg, bool ask_update, thread_context* thrd) + { + if (evt_code != arg.evt_code) + throw std::runtime_error("Nana.bedrock: invalid event arg."); + + return emit(evt_code, wd, static_cast(arg), ask_update, thrd); + } + + bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, bool ask_update, thread_context* thrd) + { + if (wd_manager.available(wd) == false) + return false; + + basic_window* prev_event_wd; + if (thrd) + { + prev_event_wd = thrd->event_window; + thrd->event_window = wd; + _m_event_filter(evt_code, wd, thrd); + } + + if (wd->other.upd_state == core_window_t::update_state::none) + wd->other.upd_state = core_window_t::update_state::lazy; + + _m_emit_core(evt_code, wd, false, arg); + + if (ask_update) + wd_manager.do_lazy_refresh(wd, false); + else if (wd_manager.available(wd)) + wd->other.upd_state = basic_window::update_state::none; + + if (thrd) thrd->event_window = prev_event_wd; + return true; + } + + bool bedrock::emit_drawer(event_code evt_code, core_window_t* wd, const ::nana::detail::event_arg_interface& arg, thread_context* thrd) + { + if (bedrock_object.wd_manager.available(wd) == false) + return false; + + core_window_t* prev_event_wd; + if (thrd) + { + prev_event_wd = thrd->event_window; + thrd->event_window = wd; + } + + if (wd->other.upd_state == core_window_t::update_state::none) + wd->other.upd_state = core_window_t::update_state::lazy; + + _m_emit_core(evt_code, wd, true, arg); + + if (thrd) thrd->event_window = prev_event_wd; + return true; + } + + const nana::char_t* translate(cursor id) + { + const nana::char_t* name = IDC_ARROW; + + switch(id) + { + case cursor::arrow: + name = IDC_ARROW; break; + case cursor::wait: + name = IDC_WAIT; break; + case cursor::hand: + name = IDC_HAND; break; + case cursor::size_we: + name = IDC_SIZEWE; break; + case cursor::size_ns: + name = IDC_SIZENS; break; + case cursor::size_bottom_left: + case cursor::size_top_right: + name = IDC_SIZENESW; break; + case cursor::size_top_left: + case cursor::size_bottom_right: + name = IDC_SIZENWSE; break; + case cursor::iterm: + name = IDC_IBEAM; break; + } + return name; + } + + void bedrock::thread_context_destroy(core_window_t * wd) + { + auto * thr = get_thread_context(0); + if (thr && thr->event_window == wd) + thr->event_window = nullptr; + } + + void bedrock::thread_context_lazy_refresh() + { + auto* thrd = get_thread_context(0); + if (thrd && thrd->event_window) + { + //the state none should be tested, becuase in an event, there would be draw after an update, + //if the none is not tested, the draw after update will not be refreshed. + switch (thrd->event_window->other.upd_state) + { + case core_window_t::update_state::none: + case core_window_t::update_state::lazy: + thrd->event_window->other.upd_state = core_window_t::update_state::refresh; + default: break; + } + } + } + + //Dynamically set a cursor for a window + void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + { + if (nullptr == thrd) + thrd = get_thread_context(wd->thread_id); + + if ((cursor::arrow == cur) && !thrd->cursor.native_handle) + return; + + thrd->cursor.window = wd; + if ((thrd->cursor.native_handle == wd->root) && (cur == thrd->cursor.predef_cursor)) + return; + + thrd->cursor.native_handle = wd->root; + if (thrd->cursor.predef_cursor != cur) + { + thrd->cursor.predef_cursor = cur; + thrd->cursor.handle = ::LoadCursor(nullptr, translate(cur)); + } + + if (wd->root_widget->other.attribute.root->running_cursor != cur) + { + wd->root_widget->other.attribute.root->running_cursor = cur; +#ifdef _WIN64 + ::SetClassLongPtr(reinterpret_cast(wd->root), GCLP_HCURSOR, + reinterpret_cast(thrd->cursor.handle)); +#else + ::SetClassLong(reinterpret_cast(wd->root), GCL_HCURSOR, + static_cast(reinterpret_cast(thrd->cursor.handle))); +#endif + } + if (cursor::arrow == thrd->cursor.predef_cursor) + { + thrd->cursor.window = nullptr; + thrd->cursor.native_handle = nullptr; + } + } + + void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + { + wd->root_widget->other.attribute.root->state_cursor = cur; + wd->root_widget->other.attribute.root->state_cursor_window = wd; + set_cursor(wd, cur, thrd); + auto cur_handle = ::LoadCursor(nullptr, translate(cur)); + ::SetCursor(cur_handle); + ::ShowCursor(TRUE); + } + + void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) + { + if (nullptr == thrd) + thrd = get_thread_context(wd->thread_id); + + HCURSOR rev_handle = ::LoadCursor(nullptr, IDC_ARROW); + if (!wd_manager.available(wd)) + { + ::ShowCursor(FALSE); + ::SetCursor(rev_handle); + return; + } + + wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow; + wd->root_widget->other.attribute.root->state_cursor_window = nullptr; + + auto pos = native_interface::cursor_position(); + auto native_handle = native_interface::find_window(pos.x, pos.y); + + if (!native_handle) + { + ::ShowCursor(FALSE); + ::SetCursor(rev_handle); + return; + } + + native_interface::calc_window_point(native_handle, pos); + auto rev_wd = wd_manager.find_window(native_handle, pos.x, pos.y); + if (rev_wd) + { + set_cursor(rev_wd, rev_wd->predef_cursor, thrd); + rev_handle = thrd->cursor.handle; + } + ::ShowCursor(FALSE); + ::SetCursor(rev_handle); + } + + void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd) + { + auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow); + + switch(event_id) + { + case event_code::mouse_enter: + if (not_state_cur) + set_cursor(wd, wd->predef_cursor, thrd); + break; + case event_code::mouse_leave: + if (not_state_cur && (wd->predef_cursor != cursor::arrow)) + set_cursor(wd, cursor::arrow, thrd); + break; + case event_code::destroy: + if (wd->root_widget->other.attribute.root->state_cursor_window == wd) + undefine_state_cursor(wd, thrd); + + if(wd == thrd->cursor.window) + { + set_cursor(wd, cursor::arrow, thrd); + wd->root_widget->other.attribute.root->running_cursor = cursor::arrow; + } + break; + default: + break; + } + } +}//end namespace detail +}//end namespace nana diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp new file mode 100644 index 00000000..6e80adb3 --- /dev/null +++ b/source/gui/detail/window_layout.cpp @@ -0,0 +1,391 @@ +/* +* Window Layout Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/detail/window_layout.hpp +* +*/ + +#include +#include +#include +#include +#include + +namespace nana +{ + namespace detail + { + //class window_layout + void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed) + { + if (nullptr == wd->effect.bground) + { + if (is_redraw) + { + if (wd->flags.refreshing) return; + + wd->flags.refreshing = true; + wd->drawer.refresh(); + wd->flags.refreshing = false; + } + maproot(wd, is_redraw, is_child_refreshed); + } + else + _m_paint_glass_window(wd, is_redraw, is_child_refreshed, false, true); + } + + bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool is_child_refreshed) + { + nana::rectangle vr; + if (read_visual_rectangle(wd, vr)) + { + //get the root graphics + auto& graph = *(wd->root_graph); + + if (wd->other.category != category::lite_widget_tag::value) + graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y)); + + _m_paste_children(wd, is_child_refreshed, have_refreshed, vr, graph, nana::point()); + + if (wd->parent) + { + std::vector blocks; + blocks.reserve(10); + if (read_overlaps(wd, vr, blocks)) + { + nana::point p_src; + for (auto & el : blocks) + { + if (el.window->other.category == category::frame_tag::value) + { + native_window_type container = el.window->other.attribute.frame->container; + native_interface::refresh_window(container); + graph.bitblt(el.r, container); + } + else + { + p_src.x = el.r.x - el.window->pos_root.x; + p_src.y = el.r.y - el.window->pos_root.y; + graph.bitblt(el.r, (el.window->drawer.graphics), p_src); + } + + _m_paste_children(el.window, is_child_refreshed, false, el.r, graph, nana::point{}); + } + } + } + _m_notify_glasses(wd, vr); + return true; + } + return false; + } + + void window_layout::paste_children_to_graphics(core_window_t* wd, nana::paint::graphics& graph) + { + _m_paste_children(wd, false, false, rectangle{ wd->pos_root, wd->dimension }, graph, wd->pos_root); + } + + //read_visual_rectangle + //@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, + // the visual rectangle is a rectangular block that a window should be displayed on screen. + // The result is a rectangle that is a visible area for its ancesters. + bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual) + { + if (false == wd->visible) return false; + + visual = rectangle{ wd->pos_root, wd->dimension }; + + if (wd->root_widget != wd) + { + //Test if the root widget is overlapped the specified widget + //the pos of root widget is (0, 0) + if (overlap(visual, rectangle{ wd->root_widget->pos_owner, wd->root_widget->dimension }) == false) + return false; + } + + for (auto* parent = wd->parent; parent; parent = parent->parent) + { + overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual); + } + + return true; + } + + //read_overlaps + // reads the overlaps that are overlapped a rectangular block + bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector& blocks) + { + wd_rectangle block; + while (wd->parent) + { + auto & siblings = wd->parent->children; + //It should be checked that whether the window is still a chlid of its parent. + if (siblings.size()) + { + auto i = &(siblings[0]); + auto *end = i + siblings.size(); + i = std::find(i, end, wd); + if (i != end) + { + //find the widget that next to wd. + for (++i; i < end; ++i) + { + core_window_t* cover = *i; + if (cover->visible && (nullptr == cover->effect.bground)) + { + if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r)) + { + block.window = cover; + blocks.push_back(block); + } + } + } + } + } + wd = wd->parent; + } + return (!blocks.empty()); + } + + bool window_layout::enable_effects_bground(core_window_t * wd, bool enabled) + { + if (wd->other.category != category::widget_tag::value) + return false; + + if (false == enabled) + { + delete wd->effect.bground; + wd->effect.bground = nullptr; + wd->effect.bground_fade_rate = 0; + } + + //Find the window whether it is registered for the bground effects + auto i = std::find(data_sect.effects_bground_windows.begin(), data_sect.effects_bground_windows.end(), wd); + if (i != data_sect.effects_bground_windows.end()) + { + //If it has already registered, do nothing. + if (enabled) + return false; + + //Disable the effect. + data_sect.effects_bground_windows.erase(i); + wd->other.glass_buffer.release(); + return true; + } + //No such effect has registered. + if (false == enabled) + return false; + + //Enable the effect. + data_sect.effects_bground_windows.push_back(wd); + wd->other.glass_buffer.make(wd->dimension.width, wd->dimension.height); + make_bground(wd); + return true; + } + + //make_bground + // update the glass buffer of a glass window. + void window_layout::make_bground(core_window_t* const wd) + { + nana::point rpos{ wd->pos_root }; + auto & glass_buffer = wd->other.glass_buffer; + + if (wd->parent->other.category == category::lite_widget_tag::value) + { + std::vector layers; + core_window_t * beg = wd->parent; + while (beg && (beg->other.category == category::lite_widget_tag::value)) + { + layers.push_back(beg); + beg = beg->parent; + } + + glass_buffer.bitblt(wd->dimension, beg->drawer.graphics, wd->pos_root - beg->pos_root); + + nana::rectangle r(wd->pos_owner, wd->dimension); + for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i) + { + core_window_t * pre = *i; + if (false == pre->visible) + continue; + + core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd); + r.x = wd->pos_root.x - pre->pos_root.x; + r.y = wd->pos_root.y - pre->pos_root.y; + for (auto child : pre->children) + { + if (child->index >= term->index) + break; + + nana::rectangle ovlp; + if (child->visible && overlap(r, rectangle(child->pos_owner, child->dimension), ovlp)) + { + if (child->other.category != category::lite_widget_tag::value) + glass_buffer.bitblt(nana::rectangle(ovlp.x - pre->pos_owner.x, ovlp.y - pre->pos_owner.y, ovlp.width, ovlp.height), child->drawer.graphics, nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y)); + ovlp.x += pre->pos_root.x; + ovlp.y += pre->pos_root.y; + _m_paste_children(child, false, false, ovlp, glass_buffer, rpos); + } + } + } + } + else + glass_buffer.bitblt(wd->dimension, wd->parent->drawer.graphics, wd->pos_owner); + + const rectangle r_of_wd{ wd->pos_owner, wd->dimension }; + for (auto child : wd->parent->children) + { + if (child->index >= wd->index) + break; + + nana::rectangle ovlp; + if (child->visible && overlap(r_of_wd, rectangle{ child->pos_owner, child->dimension }, ovlp)) + { + if (child->other.category != category::lite_widget_tag::value) + glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y)); + + ovlp.x += wd->pos_root.x; + ovlp.y += wd->pos_root.y; + _m_paste_children(child, false, false, ovlp, glass_buffer, rpos); + } + } + + if (wd->effect.bground) + wd->effect.bground->take_effect(reinterpret_cast(wd), glass_buffer); + } + + //_m_paste_children + //@brief:paste children window to the root graphics directly. just paste the visual rectangle + void window_layout::_m_paste_children(core_window_t* wd, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) + { + nana::rectangle rect; + for (auto child : wd->children) + { + //it will not past children if no drawer and visible is false. + if ((false == child->visible) || ((child->other.category != category::lite_widget_tag::value) && child->drawer.graphics.empty())) + continue; + + if (nullptr == child->effect.bground) + { + if (overlap(nana::rectangle{ child->pos_root, child->dimension }, parent_rect, rect)) + { + bool have_child_refreshed = false; + if (child->other.category != category::lite_widget_tag::value) + { + if (is_child_refreshed && (false == child->flags.refreshing)) + { + have_child_refreshed = true; + child->flags.refreshing = true; + child->drawer.refresh(); + child->flags.refreshing = false; + } + + graph.bitblt(nana::rectangle(rect.x - graph_rpos.x, rect.y - graph_rpos.y, rect.width, rect.height), + child->drawer.graphics, nana::point(rect.x - child->pos_root.x, rect.y - child->pos_root.y)); + } + _m_paste_children(child, is_child_refreshed, have_child_refreshed, rect, graph, graph_rpos); + } + } + else + { + //If have_refreshed, the glass should be notified. + _m_paint_glass_window(child, false, is_child_refreshed, have_refreshed, false); + } + } + } + + void window_layout::_m_paint_glass_window(core_window_t* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other) + { + if (wd->flags.refreshing && is_redraw) return; + + nana::rectangle vr; + if (read_visual_rectangle(wd, vr)) + { + if (is_redraw || called_by_notify) + { + if (called_by_notify) + make_bground(wd); + + wd->flags.refreshing = true; + wd->drawer.refresh(); + wd->flags.refreshing = false; + } + + auto & root_graph = *(wd->root_graph); + //Map root + root_graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y)); + _m_paste_children(wd, is_child_refreshed, (is_redraw || called_by_notify), vr, root_graph, nana::point()); + + if (wd->parent) + { + std::vector blocks; + read_overlaps(wd, vr, blocks); + for (auto & n : blocks) + { + root_graph.bitblt(n.r, (n.window->drawer.graphics), nana::point(n.r.x - n.window->pos_root.x, n.r.y - n.window->pos_root.y)); + } + } + + if (notify_other) + _m_notify_glasses(wd, vr); + } + } + + //_m_notify_glasses + //@brief: Notify the glass windows that are overlapped with the specified vis_rect + void window_layout::_m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& r_visual) + { + typedef category::flags cat_flags; + + nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); + for (auto wd : data_sect.effects_bground_windows) + { + if (wd == sigwd || !wd->visible || !wd->visible_parents() || + (false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd))) + continue; + + if (sigwd->parent == wd->parent) + { + if (sigwd->index >= wd->index) + continue; + } + else if (sigwd != wd->parent) + { + if (wd->parent && (cat_flags::lite_widget == wd->parent->other.category)) + { + //Test if sigwd is an ancestor of the glass window, and there are lite widgets + //between sigwd and glass window. + auto ancestor = wd->parent->parent; + while (ancestor && (ancestor != sigwd) && (cat_flags::lite_widget == ancestor->other.category)) + ancestor = ancestor->parent; + + if ((ancestor != sigwd) || (cat_flags::lite_widget == ancestor->other.category)) + continue; + } + else + { + //test if sigwnd is a parent of glass window x, or a slibing of the glass window, or a child of the slibing of the glass window. + core_window_t *p = wd->parent, *signode = sigwd; + while (signode->parent && (signode->parent != p)) + signode = signode->parent; + + if ((!signode->parent) || (signode->index >= wd->index)) + continue; + } + } + else + continue; + + _m_paint_glass_window(wd, true, false, true, true); + } + } + //end class window_layout + + window_layout::data_section window_layout::data_sect; + }//end namespace detail +}//end namespace nana diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp new file mode 100644 index 00000000..2c119d0f --- /dev/null +++ b/source/gui/detail/window_manager.cpp @@ -0,0 +1,1415 @@ +/* + * Window Manager Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/detail/window_manager.cpp + * + */ + +#include +#include GUI_BEDROCK_HPP +#include +#include +#include +#include +#include +#include +#include + +namespace nana +{ + +namespace detail +{ + //class window_manager + struct window_handle_deleter + { + void operator()(basic_window* wd) const + { + bedrock::instance().evt_operation.umake(reinterpret_cast(wd)); + delete wd; + } + }; + //struct wdm_private_impl + struct window_manager::wdm_private_impl + { + root_register misc_register; + handle_manager wd_register; + signal_manager signal; + paint::image default_icon; + }; + //end struct wdm_private_impl + + //class revertible_mutex + window_manager::revertible_mutex::revertible_mutex() + { + thr_.tid = 0; + thr_.refcnt = 0; + } + + void window_manager::revertible_mutex::lock() + { + std::recursive_mutex::lock(); + if(0 == thr_.tid) + thr_.tid = nana::system::this_thread_id(); + ++thr_.refcnt; + } + + bool window_manager::revertible_mutex::try_lock() + { + if(std::recursive_mutex::try_lock()) + { + if(0 == thr_.tid) + thr_.tid = nana::system::this_thread_id(); + ++thr_.refcnt; + return true; + } + return false; + } + + void window_manager::revertible_mutex::unlock() + { + if(thr_.tid == nana::system::this_thread_id()) + if(0 == --thr_.refcnt) + thr_.tid = 0; + std::recursive_mutex::unlock(); + } + + void window_manager::revertible_mutex::revert() + { + if(thr_.refcnt && (thr_.tid == nana::system::this_thread_id())) + { + std::size_t cnt = thr_.refcnt; + + stack_.push_back(thr_); + thr_.tid = 0; + thr_.refcnt = 0; + + for(std::size_t i = 0; i < cnt; ++i) + std::recursive_mutex::unlock(); + } + } + + void window_manager::revertible_mutex::forward() + { + std::recursive_mutex::lock(); + if(stack_.size()) + { + auto thr = stack_.back(); + if(thr.tid == nana::system::this_thread_id()) + { + stack_.pop_back(); + for(std::size_t i = 0; i < thr.refcnt; ++i) + std::recursive_mutex::lock(); + thr_ = thr; + } + else + throw std::runtime_error("Nana.GUI: The forward is not matched."); + } + std::recursive_mutex::unlock(); + } + //end class revertible_mutex + + //Utilities in this unit. + namespace utl + { + template + bool erase(std::vector& container, T value) + { + for (auto i = container.begin(), end = container.end(); i != end; ++i) + { + if ((*i) == value) + { + container.erase(i); + return true; + } + } + return false; + } + } + + window_manager::window_manager() + : impl_(new wdm_private_impl) + { + attr_.capture.window = nullptr; + attr_.capture.ignore_children = true; + + menu_.window = nullptr; + menu_.owner = nullptr; + menu_.has_keyboard = false; + } + + window_manager::~window_manager() + { + delete impl_; + } + + bool window_manager::is_queue(core_window_t* wd) + { + return (wd && (wd->other.category == category::root_tag::value)); + } + + std::size_t window_manager::number_of_core_window() const + { + return impl_->wd_register.size(); + } + + window_manager::mutex_type& window_manager::internal_lock() const + { + return mutex_; + } + + void window_manager::all_handles(std::vector &v) const + { + impl_->wd_register.all(v); + } + + void window_manager::signal_fire_caption(core_window_t* wd, const nana::char_t* str) + { + detail::signals sig; + sig.info.caption = str; + impl_->signal.call_signal(wd, signals::code::caption, sig); + } + + nana::string window_manager::signal_fire_caption(core_window_t* wd) + { + nana::string str; + detail::signals sig; + sig.info.str = &str; + impl_->signal.call_signal(wd, signals::code::read_caption, sig); + return str; + } + + void window_manager::event_filter(core_window_t* wd, bool is_make, event_code evtid) + { + switch(evtid) + { + case event_code::mouse_drop: + wd->flags.dropable = (is_make || (0 != wd->together.attached_events->mouse_dropfiles.length())); + break; + default: + break; + } + } + + void window_manager::default_icon(const paint::image& img) + { + impl_->default_icon = img; + } + + bool window_manager::available(core_window_t* wd) + { + return impl_->wd_register.available(wd); + } + + bool window_manager::available(core_window_t * a, core_window_t* b) + { + return (impl_->wd_register.available(a) && impl_->wd_register.available(b)); + } + + bool window_manager::available(native_window_type wd) + { + if(wd) + { + std::lock_guard lock(mutex_); + return (impl_->misc_register.find(wd) != nullptr); + } + return false; + } + + window_manager::core_window_t* window_manager::create_root(core_window_t* owner, bool nested, rectangle r, const appearance& app, widget * wdg) + { + native_window_type native = nullptr; + if(owner) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + if (impl_->wd_register.available(owner)) + { + native = (owner->other.category == category::frame_tag::value ? + owner->other.attribute.frame->container : owner->root_widget->root); + r.x += owner->pos_root.x; + r.y += owner->pos_root.y; + } + else + owner = nullptr; + } + + auto result = native_interface::create_window(native, nested, r, app); + if(result.native_handle) + { + core_window_t* wd = new core_window_t(owner, wdg, (category::root_tag**)nullptr); + wd->flags.take_active = !app.no_activate; + wd->title = native_interface::window_caption(result.native_handle); + + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + //create Root graphics Buffer and manage it + root_misc misc(wd, result.width, result.height); + auto* value = impl_->misc_register.insert(result.native_handle, misc); + + wd->bind_native_window(result.native_handle, result.width, result.height, result.extra_width, result.extra_height, value->root_graph); + impl_->wd_register.insert(wd, wd->thread_id); + + if(owner && owner->other.category == category::frame_tag::value) + insert_frame(owner, wd); + + bedrock::inc_window(wd->thread_id); + this->icon(wd, impl_->default_icon); + return wd; + } + return nullptr; + } + + window_manager::core_window_t* window_manager::create_frame(core_window_t* parent, const rectangle& r, widget* wdg) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + if (impl_->wd_register.available(parent) == false) return nullptr; + + core_window_t * wd = new core_window_t(parent, r, wdg, (category::frame_tag**)nullptr); + wd->frame_window(native_interface::create_child_window(parent->root, rectangle(wd->pos_root.x, wd->pos_root.y, r.width, r.height))); + impl_->wd_register.insert(wd, wd->thread_id); + + //Insert the frame_widget into its root frames container. + wd->root_widget->other.attribute.root->frames.push_back(wd); + return (wd); + } + + bool window_manager::insert_frame(core_window_t* frame, native_window wd) + { + if(frame) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if(frame->other.category == category::frame_tag::value) + frame->other.attribute.frame->attach.push_back(wd); + return true; + } + return false; + } + + bool window_manager::insert_frame(core_window_t* frame, core_window_t* wd) + { + if(frame) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if(frame->other.category == category::frame_tag::value) + { + if (impl_->wd_register.available(wd) && wd->other.category == category::root_tag::value && wd->root != frame->root) + { + frame->other.attribute.frame->attach.push_back(wd->root); + return true; + } + } + } + return false; + } + + window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(parent) == false) + return nullptr; + + core_window_t * wd; + if(is_lite) + wd = new core_window_t(parent, r, wdg, (category::lite_widget_tag**)nullptr); + else + wd = new core_window_t(parent, r, wdg, (category::widget_tag**)nullptr); + impl_->wd_register.insert(wd, wd->thread_id); + return wd; + } + + void window_manager::close(core_window_t *wd) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + if(wd->other.category == category::root_tag::value) + { + auto &brock = bedrock::instance(); + arg_unload arg; + arg.window_handle = reinterpret_cast(wd); + arg.cancel = false; + brock.emit(event_code::unload, wd, arg, true, brock.get_thread_context()); + if (false == arg.cancel) + { + //Before close the window, its owner window should be actived, otherwise other window will be + //activated due to the owner window is not enabled. + if(wd->flags.modal || (wd->owner == nullptr) || wd->owner->flags.take_active) + native_interface::activate_owner(wd->root); + + //Close should detach the drawer and send destroy signal to widget object. + //Otherwise, when a widget object is been deleting in other thread by delete operator, the object will be destroyed + //before the window_manager destroyes the window, and then, window_manager detaches the + //non-existing drawer_trigger which is destroyed by destruction of widget. Crash! + wd->drawer.detached(); + impl_->signal.call_signal(wd, signals::code::destroy, signals_); + impl_->signal.umake(wd); + + native_interface::close_window(wd->root); + } + } + else + destroy(wd); + } + + //destroy + //@brief: Delete the window handle + void window_manager::destroy(core_window_t* wd) + { + core_window_t* parent = nullptr; + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + if (wd->parent) + { + parent = wd->parent; + utl::erase(wd->parent->children, wd); + } + + _m_destroy(wd); + } + update(parent, false, false); + } + + //destroy_handle + //@brief: Delete window handle, the handle type must be a root and a frame. + void window_manager::destroy_handle(core_window_t* wd) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + if((wd->other.category == category::root_tag::value) || (wd->other.category != category::frame_tag::value)) + { + impl_->misc_register.erase(wd->root); + impl_->wd_register.remove(wd); + } + } + + void window_manager::icon(core_window_t* wd, const paint::image& img) + { + if(false == img.empty()) + { + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + if(wd->other.category == category::root_tag::value) + native_interface::window_icon(wd->root, img); + } + } + } + + //show + //@brief: show or hide a window + bool window_manager::show(core_window_t* wd, bool visible) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + if(visible != wd->visible) + { + native_window_type nv = nullptr; + switch(wd->other.category) + { + case category::root_tag::value: + nv = wd->root; break; + case category::frame_tag::value: + nv = wd->other.attribute.frame->container; break; + default: //category::widget_tag, category::lite_widget_tag + break; + } + + if(visible && wd->effect.bground) + wndlayout_type::make_bground(wd); + + //Don't set the visible attr of a window if it is a root. + //The visible attr of a root will be set in the expose event. + if(category::root_tag::value != wd->other.category) + bedrock::instance().event_expose(wd, visible); + + if(nv) + native_interface::show_window(nv, visible, wd->flags.take_active); + } + return true; + } + return false; + } + + window_manager::core_window_t* window_manager::find_window(native_window_type root, int x, int y) + { + if (nullptr == root) + return nullptr; + + if((false == attr_.capture.ignore_children) || (nullptr == attr_.capture.window) || (attr_.capture.window->root != root)) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + auto rrt = root_runtime(root); + point pos{ x, y }; + if (rrt && _m_effective(rrt->window, pos)) + return _m_find(rrt->window, pos); + } + return attr_.capture.window; + } + + //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window + bool window_manager::move(core_window_t* wd, int x, int y, bool passive) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + if(wd->other.category != category::root_tag::value) + { + //Move child widgets + if(x != wd->pos_owner.x || y != wd->pos_owner.y) + { + point delta{ x - wd->pos_owner.x, y - wd->pos_owner.y }; + + wd->pos_owner.x = x; + wd->pos_owner.y = y; + _m_move_core(wd, delta); + + if(wd->together.caret && wd->together.caret->visible()) + wd->together.caret->update(); + + auto &brock = bedrock::instance(); + arg_move arg; + arg.window_handle = reinterpret_cast(wd); + arg.x = x; + arg.y = y; + brock.emit(event_code::move, wd, arg, true, brock.get_thread_context()); + return true; + } + } + else if(false == passive) + native_interface::move_window(wd->root, x, y); + } + + return false; + } + + bool window_manager::move(core_window_t* wd, const rectangle& r) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (!impl_->wd_register.available(wd)) + return false; + + auto & brock = bedrock::instance(); + bool moved = false; + const bool size_changed = (r.width != wd->dimension.width || r.height != wd->dimension.height); + if(wd->other.category != category::root_tag::value) + { + //Move child widgets + if(r.x != wd->pos_owner.x || r.y != wd->pos_owner.y) + { + point delta{ r.x - wd->pos_owner.x, r.y - wd->pos_owner.y }; + wd->pos_owner.x = r.x; + wd->pos_owner.y = r.y; + _m_move_core(wd, delta); + moved = true; + + if(wd->together.caret && wd->together.caret->visible()) + wd->together.caret->update(); + + arg_move arg; + arg.window_handle = reinterpret_cast(wd); + arg.x = r.x; + arg.y = r.y; + brock.emit(event_code::move, wd, arg, true, brock.get_thread_context()); + } + + if(size_changed) + size(wd, nana::size{r.width, r.height}, true, false); + } + else + { + if(size_changed) + { + wd->dimension.width = r.width; + wd->dimension.height = r.height; + wd->drawer.graphics.make(r.width, r.height); + wd->root_graph->make(r.width, r.height); + native_interface::move_window(wd->root, r); + + arg_resized arg; + arg.window_handle = reinterpret_cast(wd); + arg.width = r.width; + arg.height = r.height; + brock.emit(event_code::resized, wd, arg, true, brock.get_thread_context()); + } + else + native_interface::move_window(wd->root, r.x, r.y); + } + + return (moved || size_changed); + } + + //size + //@brief: Size a window + //@param: passive, if it is true, the function would not change the size if wd is a root_widget. + // e.g, when the size of window is changed by OS/user, the function should not resize the + // window again, otherwise, it causes an infinite loop, because when a root_widget is resized, + // window_manager will call the function. + bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (!impl_->wd_register.available(wd)) + return false; + + auto & brock = bedrock::instance(); + if (sz != wd->dimension) + { + arg_resizing arg; + arg.window_handle = reinterpret_cast(wd); + arg.border = window_border::none; + arg.width = sz.width; + arg.height = sz.height; + brock.emit(event_code::resizing, wd, arg, false, brock.get_thread_context()); + sz.width = arg.width; + sz.height = arg.height; + } + + if(wd->max_track_size.width && wd->max_track_size.height) + { + if(sz.width > wd->max_track_size.width) + sz.width = wd->max_track_size.width; + if(sz.height > wd->max_track_size.height) + sz.height = wd->max_track_size.height; + } + if(wd->min_track_size.width && wd->min_track_size.height) + { + if(sz.width < wd->min_track_size.width) + sz.width = wd->min_track_size.width; + if(sz.height < wd->min_track_size.height) + sz.height = wd->min_track_size.height; + } + + if (wd->dimension == sz) + return false; + + wd->dimension = sz; + + if(category::lite_widget_tag::value != wd->other.category) + { + bool graph_state = wd->drawer.graphics.empty(); + wd->drawer.graphics.make(sz.width, sz.height); + + //It shall make a typeface_changed() call when the graphics state is changing. + //Because when a widget is created with zero-size, it may get some wrong result in typeface_changed() call + //due to the invaliable graphics object. + if(graph_state != wd->drawer.graphics.empty()) + wd->drawer.typeface_changed(); + + if(category::root_tag::value == wd->other.category) + { + wd->root_graph->make(sz.width, sz.height); + if(false == passive) + native_interface::window_size(wd->root, sz + nana::size(wd->extra_width, wd->extra_height)); + } + else if(category::frame_tag::value == wd->other.category) + { + native_interface::window_size(wd->other.attribute.frame->container, sz); + for(auto natwd : wd->other.attribute.frame->attach) + native_interface::window_size(natwd, sz); + } + else + { + //update the bground buffer of glass window. + if(wd->effect.bground && wd->parent) + { + wd->other.glass_buffer.make(sz.width, sz.height); + wndlayout_type::make_bground(wd); + } + } + } + + arg_resized arg; + arg.window_handle = reinterpret_cast(wd); + arg.width = sz.width; + arg.height = sz.height; + brock.emit(event_code::resized, wd, arg, ask_update, brock.get_thread_context()); + return true; + } + + window_manager::core_window_t* window_manager::root(native_window_type wd) const + { + static std::pair cache; + if(cache.first == wd) return cache.second; + + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + auto rrt = root_runtime(wd); + if(rrt) + { + cache.first = wd; + cache.second = rrt->window; + return cache.second; + } + return nullptr; + } + + //Copy the root buffer that wnd specified into DeviceContext + void window_manager::map(core_window_t* wd) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + //Copy the root buffer that wd specified into DeviceContext +#if defined(NANA_LINUX) + wd->drawer.map(reinterpret_cast(wd)); +#elif defined(NANA_WINDOWS) + if(nana::system::this_thread_id() == wd->thread_id) + wd->drawer.map(reinterpret_cast(wd)); + else + bedrock::instance().map_thread_root_buffer(wd); +#endif + } + } + + //update + //@brief: update is used for displaying the screen-off buffer. + // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the + // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh + bool window_manager::update(core_window_t* wd, bool redraw, bool force) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return false; + + if (wd->visible && wd->visible_parents()) + { + if(force || (false == wd->belong_to_lazy())) + { + wndlayout_type::paint(wd, redraw, false); + this->map(wd); + } + else + { + if(redraw) + wndlayout_type::paint(wd, true, false); + if(wd->other.upd_state == core_window_t::update_state::lazy) + wd->other.upd_state = core_window_t::update_state::refresh; + } + } + return true; + } + + void window_manager::refresh_tree(core_window_t* wd) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + //It's not worthy to redraw if visible is false + if (impl_->wd_register.available(wd) && wd->visible && wd->visible_parents()) + wndlayout_type::paint(wd, true, true); + } + + //do_lazy_refresh + //@brief: defined a behavior of flush the screen + //@return: it returns true if the wnd is available + bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + //It's not worthy to redraw if visible is false + if (false == impl_->wd_register.available(wd)) + return false; + + if(wd->visible) + { + if (wd->visible_parents()) + { + if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen) + { + wndlayout_type::paint(wd, false, false); + this->map(wd); + } + } + else + wndlayout_type::paint(wd, true, false); //only refreshing if it has an invisible parent + } + wd->other.upd_state = core_window_t::update_state::none; + return true; + } + + //get_graphics + //@brief: Get a copy of the graphics object of a window. + // the copy of the graphics object has a same buf handle with the graphics object's, they are count-refered + // here returns a reference that because the framework does not guarantee the wnd's + // graphics object available after a get_graphics call. + bool window_manager::get_graphics(core_window_t* wd, nana::paint::graphics& result) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (!impl_->wd_register.available(wd)) + return false; + + result.make(wd->drawer.graphics.width(), wd->drawer.graphics.height()); + result.bitblt(0, 0, wd->drawer.graphics); + wndlayout_type::paste_children_to_graphics(wd, result); + return true; + } + + bool window_manager::get_visual_rectangle(core_window_t* wd, nana::rectangle& r) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + return (impl_->wd_register.available(wd) ? + wndlayout_type::read_visual_rectangle(wd, r) : + false); + } + + ::nana::widget* window_manager::get_widget(core_window_t* wd) const + { + std::lock_guard lock(mutex_); + return (impl_->wd_register.available(wd) ? wd->widget_ptr : nullptr); + } + + std::vector window_manager::get_children(core_window_t* wd) const + { + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + return wd->children; + return{}; + } + + bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (!impl_->wd_register.available(wd)) + return false; + + if ((category::flags::lite_widget != wd->other.category) && (category::flags::widget != wd->other.category)) + return false; + + if (impl_->wd_register.available(newpa) && (nullptr == wd->owner) && (wd->parent != newpa) && (!wd->flags.modal)) + { + //Check the newpa's parent. If wd is ancestor of newpa, return false. + if (wd->is_ancestor_of(newpa->parent)) + return false; + + auto wdpa = wd->parent; + this->_m_disengage(wd, newpa); + this->update(wdpa, true, true); + this->update(wd, false, true); + return true; + } + return false; + } + + //set_focus + //@brief: set a keyboard focus to a window. this may fire a focus event. + window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + if (!impl_->wd_register.available(wd)) + return nullptr; + + auto & brock = bedrock::instance(); + auto root_wd = wd->root_widget; + auto prev_focus = root_wd->other.attribute.root->focus; + + arg_focus arg; + if(wd != prev_focus) + { + //kill the previous window focus + root_wd->other.attribute.root->focus = wd; + + if (impl_->wd_register.available(prev_focus)) + { + if(prev_focus->together.caret) + prev_focus->together.caret->set_active(false); + + arg.getting = false; + arg.window_handle = reinterpret_cast(prev_focus); + arg.receiver = wd->root; + brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context()); + } + } + else if(wd->root == native_interface::get_focus_window()) + wd = nullptr; //no new focus_window + + if(wd) + { + if(wd->together.caret) + wd->together.caret->set_active(true); + + arg.window_handle = reinterpret_cast(wd); + arg.getting = true; + arg.receiver = wd->root; + brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context()); + + if (!root_has_been_focused) + native_interface::set_focus(root_wd->root); + + brock.set_menubar_taken(wd); + } + return prev_focus; + } + + window_manager::core_window_t* window_manager::capture_redirect(core_window_t* wd) + { + if(attr_.capture.window && (attr_.capture.ignore_children == false) && (attr_.capture.window != wd)) + { + //Tests if the wd is a child of captured window, + //and returns the wd if it is. + if (attr_.capture.window->is_ancestor_of(wd)) + return wd; + } + return attr_.capture.window; + } + + void window_manager::capture_ignore_children(bool ignore) + { + attr_.capture.ignore_children = ignore; + } + + bool window_manager::capture_window_entered(int root_x, int root_y, bool& prev) + { + if(attr_.capture.window) + { + bool inside = _m_effective(attr_.capture.window, point{ root_x, root_y }); + if(inside != attr_.capture.inside) + { + prev = attr_.capture.inside; + attr_.capture.inside = inside; + return true; + } + } + return false; + } + + window_manager::core_window_t * window_manager::capture_window() const + { + return attr_.capture.window; + } + + //capture_window + //@brief: set a window that always captures the mouse event if it is not in the range of window + //@return: this function dose return the previous captured window. If the wnd set captured twice, + // the return value is NULL + window_manager::core_window_t* window_manager::capture_window(core_window_t* wd, bool value) + { + nana::point pos = native_interface::cursor_position(); + auto & attr_cap = attr_.capture.history; + + if(value) + { + if(wd != attr_.capture.window) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + if (impl_->wd_register.available(wd)) + { + wd->flags.capture = true; + native_interface::capture_window(wd->root, value); + auto prev = attr_.capture.window; + if(prev && (prev != wd)) + attr_cap.emplace_back(prev, attr_.capture.ignore_children); + + attr_.capture.window = wd; + attr_.capture.ignore_children = true; + native_interface::calc_window_point(wd->root, pos); + attr_.capture.inside = _m_effective(wd, pos); + return prev; + } + } + return attr_.capture.window; + } + else if(wd == attr_.capture.window) + { + attr_.capture.window = nullptr; + if(attr_cap.size()) + { + std::pair last = attr_cap.back(); + attr_cap.pop_back(); + + if (impl_->wd_register.available(last.first)) + { + attr_.capture.window = last.first; + attr_.capture.ignore_children = last.second; + native_interface::capture_window(last.first->root, true); + native_interface::calc_window_point(last.first->root, pos); + attr_.capture.inside = _m_effective(last.first, pos); + } + } + + if(wd && (nullptr == attr_.capture.window)) + native_interface::capture_window(wd->root, false); + } + else + { + auto i = std::find_if(attr_cap.begin(), attr_cap.end(), + [wd](const std::pair & x){ return (x.first == wd);}); + + if(i != attr_cap.end()) + attr_cap.erase(i); + return attr_.capture.window; + } + return wd; + } + + //enable_tabstop + //@brief: when users press a TAB, the focus should move to the next widget. + // this method insert a window which catchs an user TAB into a TAB window container + // the TAB window container is held by a wd's root widget. Not every widget has a TAB window container, + // the container is created while a first Tab Window is setting + void window_manager::enable_tabstop(core_window_t* wd) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) && (detail::tab_type::none == wd->flags.tab)) + { + wd->root_widget->other.attribute.root->tabstop.push_back(wd); + wd->flags.tab |= detail::tab_type::tabstop; + } + } + + auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (!impl_->wd_register.available(wd)) + return nullptr; + + auto & tabs = wd->root_widget->other.attribute.root->tabstop; + if (tabs.size()) + { + if (forward) // + { + if (detail::tab_type::none == wd->flags.tab) + return (tabs.front()); + else if (detail::tab_type::tabstop & wd->flags.tab) + { + auto end = tabs.cend(); + auto i = std::find(tabs.cbegin(), end, wd); + if (i != end) + { + ++i; + core_window_t* ts = (i != end ? (*i) : tabs.front()); + return (ts != wd ? ts : 0); + } + else + return tabs.front(); + } + } + else if (tabs.size() > 1) //at least 2 elments in tabs is required when moving perviously. + { + auto i = std::find(tabs.cbegin(), tabs.cend(), wd); + if (i != tabs.cend()) + return (tabs.cbegin() == i ? tabs.back() : *(i - 1)); + } + } + return nullptr; + } + + void window_manager::remove_trash_handle(unsigned tid) + { + impl_->wd_register.delete_trash(tid); + } + + bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + return wndlayout_type::enable_effects_bground(wd, enabled); + + return false; + } + + bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + if(native_interface::calc_window_point(wd->root, pos)) + { + pos -= wd->pos_root; + return true; + } + } + return false; + } + + root_misc* window_manager::root_runtime(native_window_type native_wd) const + { + return impl_->misc_register.find(native_wd); + } + + bool window_manager::register_shortkey(core_window_t* wd, unsigned long key) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + auto object = root_runtime(wd->root); + if(object) + return object->shortkeys.make(reinterpret_cast(wd), key); + } + return false; + } + + void window_manager::unregister_shortkey(core_window_t* wd, bool with_children) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + auto root_rt = root_runtime(wd->root); + if (root_rt) + { + root_rt->shortkeys.umake(reinterpret_cast(wd)); + if (with_children) + { + for (auto child : wd->children) + unregister_shortkey(child, true); + } + } + } + + auto window_manager::shortkeys(core_window_t* wd, bool with_children) -> std::vector> + { + std::vector> result; + + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd)) + { + auto root_rt = root_runtime(wd->root); + if (root_rt) + { + auto keys = root_rt->shortkeys.keys(reinterpret_cast(wd)); + for (auto key : keys) + result.emplace_back(wd, key); + + if (with_children) + { + for (auto child : wd->children) + { + auto child_keys = shortkeys(child, true); + std::copy(child_keys.cbegin(), child_keys.cend(), std::back_inserter(result)); + } + } + } + } + + return result; + } + + window_manager::core_window_t* window_manager::find_shortkey(native_window_type native_window, unsigned long key) + { + if(native_window) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + auto object = root_runtime(native_window); + if(object) + return reinterpret_cast(object->shortkeys.find(key)); + } + return nullptr; + } + + void window_manager::_m_attach_signal(core_window_t* wd, signal_invoker_interface* si) + { + impl_->signal.make(wd, si); + } + + bool check_tree(basic_window* wd, basic_window* const cond) + { + if (wd == cond) return true; + for (auto child : wd->children) + { + if (check_tree(child, cond)) + return true; + } + return false; + } + + void window_manager::_m_disengage(core_window_t* wd, core_window_t* for_new) + { + auto * const wdpa = wd->parent; + bool established = (for_new && wdpa != for_new); + decltype(for_new->root_widget->other.attribute.root) pa_root_attr = nullptr; + + if (established) + pa_root_attr = for_new->root_widget->other.attribute.root; + + auto * root_attr = wd->root_widget->other.attribute.root; + + //Holds the shortkeys of wd and its children, and then + //register these shortkeys for establishing. + std::vector> sk_holder; + + if ((!established) || (pa_root_attr != root_attr)) + { + if (established) + { + if (check_tree(wd, attr_.capture.window)) + capture_window(attr_.capture.window, false); + + if (root_attr->focus && check_tree(wd, root_attr->focus)) + root_attr->focus = nullptr; + + if (root_attr->menubar && check_tree(wd, root_attr->menubar)) + root_attr->menubar = nullptr; + + sk_holder = shortkeys(wd, true); + } + else + { + if (wd == attr_.capture.window) + capture_window(attr_.capture.window, false); + + if (root_attr->focus == wd) + root_attr->focus = nullptr; + + if (root_attr->menubar == wd) + root_attr->menubar = nullptr; + } + + if (wd->other.category == category::root_tag::value) + { + root_runtime(wd->root)->shortkeys.clear(); + wd->other.attribute.root->focus = nullptr; + } + else + { + //Unregister all the children's shortkey, if it is disengaged for reset of parent. + unregister_shortkey(wd, !established); + } + + //test if wd is a TABSTOP window + if (wd->flags.tab & detail::tab_type::tabstop) + { + auto & tabstop = root_attr->tabstop; + //remove wd from root_attr, and then add it to pa_root_attr if established. + auto wd_removed = utl::erase(tabstop, wd); + if (established) + { + if (wd_removed) + pa_root_attr->tabstop.push_back(wd); + + for (auto child : wd->children) + { + if(utl::erase(tabstop, child)) + pa_root_attr->tabstop.push_back(child); + } + } + } + } + + if (!established) + { + if (effects::edge_nimbus::none != wd->effect.edge_nimbus) + { + auto & cont = root_attr->effects_edge_nimbus; + for (auto i = cont.begin(); i != cont.end(); ++i) + { + if (i->window == wd) + { + cont.erase(i); + break; + } + } + } + } + else if (pa_root_attr != root_attr) + { + auto & cont = root_attr->effects_edge_nimbus; + for (auto i = cont.begin(); i != cont.end();) + { + if ((i->window == wd) || wd->is_ancestor_of(i->window)) + { + pa_root_attr->effects_edge_nimbus.push_back(*i); + i = cont.erase(i); + continue; + } + ++i; + } + } + + if (wd->parent) + { + auto & pa_children = wd->parent->children; + + if (pa_children.size() > 1) + { + for (auto i = pa_children.cbegin(), end = pa_children.cend(); i != end; ++i) + { + if (((*i)->index) > (wd->index)) + { + for (; i != end; ++i) + --((*i)->index); + break; + } + } + } + + if (established) + { + utl::erase(pa_children, wd); + if (for_new->children.empty()) + wd->index = 0; + else + wd->index = for_new->children.back()->index + 1; + for_new->children.push_back(wd); + } + } + + if (wd->other.category == category::frame_tag::value) + { + //remove the frame handle from the WM frames manager. + utl::erase(root_attr->frames, wd); + + if (established) + pa_root_attr->frames.push_back(wd); + } + + if (established) + { + wd->parent = for_new; + wd->root = for_new->root; + wd->root_graph = for_new->root_graph; + wd->root_widget = for_new->root_widget; + + wd->pos_owner.x = wd->pos_owner.y = 0; + + auto delta_pos = wd->pos_root - for_new->pos_root; + + std::function set_pos_root; + set_pos_root = [&set_pos_root](core_window_t* wd, const nana::point& delta_pos) + { + wd->pos_root -= delta_pos; + for (auto child : wd->children) + { + child->root = wd->root; + child->root_graph = wd->root_graph; + child->root_widget = wd->root_widget; + set_pos_root(child, delta_pos); + } + }; + + set_pos_root(wd, delta_pos); + + for (auto & keys : sk_holder) + register_shortkey(keys.first, keys.second); + } + } + + void window_manager::_m_destroy(core_window_t* wd) + { + if(wd->flags.destroying) return; + + bedrock & brock = bedrock::instance(); + brock.thread_context_destroy(wd); + + wd->flags.destroying = true; + + if(wd->together.caret) + { + //The deletion of caret wants to know whether the window is destroyed under SOME platform. Such as X11 + delete wd->together.caret; + wd->together.caret = nullptr; + } + //Delete the children widgets. + for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end; ++i) + _m_destroy(*i); + wd->children.clear(); + + arg_destroy arg; + arg.window_handle = reinterpret_cast(wd); + brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); + + _m_disengage(wd, nullptr); + wndlayout_type::enable_effects_bground(wd, false); + + wd->drawer.detached(); + impl_->signal.call_signal(wd, signals::code::destroy, signals_); + impl_->signal.umake(wd); + + if(wd->other.category == category::frame_tag::value) + { + //The frame widget does not have an owner, and close their element windows without activating owner. + //close the frame container window, it's a native window. + for(auto i : wd->other.attribute.frame->attach) + native_interface::close_window(i); + + native_interface::close_window(wd->other.attribute.frame->container); + } + + if(wd->other.category != category::flags::root) //Not a root window + impl_->wd_register.remove(wd); + } + + void window_manager::_m_move_core(core_window_t* wd, const point& delta) + { + if(wd->other.category != category::root_tag::value) //A root widget always starts at (0, 0) and its childs are not to be changed + { + wd->pos_root += delta; + if(wd->other.category == category::frame_tag::value) + native_interface::move_window(wd->other.attribute.frame->container, wd->pos_root.x, wd->pos_root.y); + + for (auto child : wd->children) + _m_move_core(child, delta); + } + } + + //_m_find + //@brief: find a window on root window through a given root coordinate. + // the given root coordinate must be in the rectangle of wnd. + window_manager::core_window_t* window_manager::_m_find(core_window_t* wd, const point& pos) + { + if(!wd->visible) + return nullptr; + + for(auto i = wd->children.rbegin(); i != wd->children.rend(); ++i) + { + core_window_t* child = *i; + if((child->other.category != category::root_tag::value) && _m_effective(child, pos)) + { + child = _m_find(child, pos); + if(child) + return child; + } + } + return wd; + } + + //_m_effective, test if the window is a handle of window that specified by (root_x, root_y) + bool window_manager::_m_effective(core_window_t* wd, const point& root_pos) + { + if(wd == nullptr || false == wd->visible) return false; + return rectangle{ wd->pos_root, wd->dimension }.is_hit(root_pos); + } + //end class window_manager +}//end namespace detail +}//end namespace nana diff --git a/source/gui/dragger.cpp b/source/gui/dragger.cpp new file mode 100644 index 00000000..dac2c6c8 --- /dev/null +++ b/source/gui/dragger.cpp @@ -0,0 +1,219 @@ + +#include + +namespace nana +{ + class dragger::dragger_impl_t + { + struct drag_target_t + { + window wd; + rectangle restrict_area; + arrange move_direction; + point origin; + + drag_target_t(window w, const rectangle& r, arrange m) + : wd(w), restrict_area(r), move_direction(m) + {} + }; + + struct trigger_t + { + window wd; + event_handle press; + event_handle over; + event_handle release; + event_handle destroy; + }; + public: + dragger_impl_t() + : dragging_(false) + {} + + ~dragger_impl_t() + { + _m_clear_triggers(); + } + + void drag_target(window wd, const rectangle& restrict_area, arrange arg) + { + for (auto & td : targets_) + { + if (td.wd == wd) + { + td.restrict_area = restrict_area; + td.move_direction = arg; + return; + } + } + targets_.emplace_back(wd, restrict_area, arg); + } + + void remove_target(window wd) + { + for (auto i = targets_.begin(); i != targets_.end(); ++i) + { + if (i->wd == wd) + { + targets_.erase(i); + return; + } + } + } + + void trigger(window wd) + { + trigger_t tg; + tg.wd = wd; + auto fn = std::bind(&dragger_impl_t::_m_trace, this, std::placeholders::_1); + auto & events = API::events(wd); + tg.press = events.mouse_down.connect(fn); + tg.over = events.mouse_move.connect(fn); + tg.release = events.mouse_up.connect(fn); + tg.destroy = events.destroy.connect([this](const arg_destroy& arg){ + _m_destroy(arg.window_handle); + }); + + triggers_.push_back(tg); + } + private: + void _m_clear_triggers() + { + for(auto & t : triggers_) + { + API::umake_event(t.press); + API::umake_event(t.over); + API::umake_event(t.release); + API::umake_event(t.destroy); + API::capture_window(t.wd, false); + } + triggers_.clear(); + } + + void _m_destroy(::nana::window wd) + { + for(auto i = triggers_.begin(), end = triggers_.end(); i != end; ++i) + { + if(i->wd == wd) + { + triggers_.erase(i); + API::capture_window(wd, false); + return; + } + } + } + + void _m_check_restrict_area(nana::point & pos, const nana::size & size, const nana::rectangle& restr_area) + { + if ((pos.x > 0) && (static_cast(size.width) + pos.x > restr_area.right())) + pos.x = restr_area.right() - static_cast(size.width); + + if (pos.x < restr_area.x) + pos.x = restr_area.x; + + if ((pos.y > 0) && (static_cast(size.height) + pos.y > restr_area.bottom())) + pos.y = restr_area.bottom() - static_cast(size.height); + + if (pos.y < restr_area.y) + pos.y = restr_area.y; + } + + void _m_trace(const arg_mouse& arg) + { + switch(arg.evt_code) + { + case event_code::mouse_down: + dragging_ = true; + API::capture_window(arg.window_handle, true); + origin_ = API::cursor_position(); + for(auto & t : targets_) + { + t.origin = API::window_position(t.wd); + window owner = API::get_owner_window(t.wd); + if(owner) + API::calc_screen_point(owner, t.origin); + } + break; + case event_code::mouse_move: + if(dragging_ && arg.left_button) + { + auto pos = API::cursor_position(); + pos -= origin_; + + for(auto & t : targets_) + { + if(API::is_window_zoomed(t.wd, true) == false) + { + auto owner = API::get_owner_window(t.wd); + auto wdps = t.origin; + if (owner) + API::calc_window_point(owner, wdps); + + switch (t.move_direction) + { + case nana::arrange::horizontal: + wdps.x += pos.x; + break; + case nana::arrange::vertical: + wdps.y += pos.y; + break; + default: + wdps += pos; + } + + if (!t.restrict_area.empty()) + _m_check_restrict_area(wdps, API::window_size(t.wd), t.restrict_area); + + API::move_window(t.wd, wdps.x, wdps.y); + } + } + } + break; + case event_code::mouse_up: + API::capture_window(arg.window_handle, false); + dragging_ = false; + break; + default: + break; + } + } + + private: + bool dragging_; + nana::point origin_; + std::vector targets_; + std::vector triggers_; + }; + + //class dragger + dragger::dragger() + : impl_(new dragger_impl_t) + { + } + + dragger::~dragger() + { + delete impl_; + } + + void dragger::target(window wd) + { + impl_->drag_target(wd, rectangle(), nana::arrange::horizontal_vertical); + } + + void dragger::target(window wd, const rectangle& restrict_area, nana::arrange arg) + { + impl_->drag_target(wd, restrict_area, arg); + } + + void dragger::remove_target(window wd) + { + impl_->remove_target(wd); + } + + void dragger::trigger(window tg) + { + impl_->trigger(tg); + } + //end class dragger +}//end namespace nana diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp new file mode 100644 index 00000000..e524d2e5 --- /dev/null +++ b/source/gui/drawing.cpp @@ -0,0 +1,86 @@ +/* + * A Drawing Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/drawing.cpp + */ + +#include +#include +#include + +namespace nana +{ + //restrict + //@brief: This name is only visible for this compiling-unit + namespace restrict + { + typedef detail::bedrock::core_window_t core_window_t; + extern detail::bedrock& bedrock; + + inline detail::drawer& get_drawer(window wd) + { + return reinterpret_cast(wd)->drawer; + } + } + + //class drawing + drawing::drawing(window wd) + :handle_(wd) + {} + + drawing::~drawing(){} //Just for polymorphism + + bool drawing::empty() const + { + return API::empty_window(handle_) || reinterpret_cast(handle_)->root_graph->empty(); + } + + void drawing::update() const + { + API::refresh_window(handle_); + } + + void drawing::draw(const draw_fn_t& f) + { + if(API::empty_window(handle_)) return; + restrict::get_drawer(handle_).draw(draw_fn_t(f), false); + } + + void drawing::draw(draw_fn_t&& f) + { + if(API::empty_window(handle_)) return; + restrict::get_drawer(handle_).draw(std::move(f), false); + } + + drawing::diehard_t drawing::draw_diehard(const draw_fn_t& f) + { + if(API::empty_window(handle_)) return nullptr; + return reinterpret_cast(restrict::get_drawer(handle_).draw(draw_fn_t(f), true)); + } + + drawing::diehard_t drawing::draw_diehard(draw_fn_t&& f) + { + if(API::empty_window(handle_)) return nullptr; + return reinterpret_cast(restrict::get_drawer(handle_).draw(std::move(f), true)); + } + + void drawing::erase(diehard_t d) + { + if(API::empty_window(handle_)) + restrict::get_drawer(handle_).erase(d); + } + + void drawing::clear() + { + if(API::empty_window(handle_)) return; + restrict::get_drawer(handle_).clear(); + } + //end class drawing +}//end namespace nana + diff --git a/source/gui/effects.cpp b/source/gui/effects.cpp new file mode 100644 index 00000000..8ed77777 --- /dev/null +++ b/source/gui/effects.cpp @@ -0,0 +1,78 @@ +#include +#include + +namespace nana +{ + namespace effects + { + bground_interface::~bground_interface() + {} + + bground_factory_interface::~bground_factory_interface() + {} + + //Here defines some effect implementations. + namespace impl + { + class transparent + : public bground_interface + { + public: + transparent(std::size_t percent) + : fade_rate_( percent <= 100 ? double(percent) / 100.0 : 0) + {} + + void take_effect(window wd, graph_reference graph) const + { + if(fade_rate_ < 0.001) + return; + + nana::color_t color = API::background(wd); + graph.blend(graph.size(), color, fade_rate_); + } + private: + const double fade_rate_; + }; + + class blur + : public bground_interface + { + public: + blur(std::size_t radius) + :radius_(radius) + {} + + void take_effect(window, graph_reference graph) const + { + graph.blur(graph.size(), radius_); + } + private: + const std::size_t radius_; + }; + }//end namespace impl + + + + //class bground_transparent + bground_transparent::bground_transparent(std::size_t percent) + : percent_(percent) + {} + + bground_interface* bground_transparent::create() const + { + return new impl::transparent(percent_); + } + //end class bgroun_transparent + + //class bground_blur + bground_blur::bground_blur(std::size_t radius) + : radius_(radius) + {} + + bground_interface * bground_blur::create() const + { + return new impl::blur(radius_); + } + //end class bground_blur + } +}//end namespace nana \ No newline at end of file diff --git a/source/gui/element.cpp b/source/gui/element.cpp new file mode 100644 index 00000000..e7eb758c --- /dev/null +++ b/source/gui/element.cpp @@ -0,0 +1,820 @@ +#include +#include +#include +#include +#include +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) + #include +#else + #include +#endif + +namespace nana +{ + //Element definitions + namespace element + { + class crook + : public crook_interface + { + bool draw(graph_reference graph, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override + { + if(crook_data.radio) + { + unsigned bmp_unchecked[12][12] = { + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCFD0D0, 0xAAABAB, 0x919292, 0x919292, 0xAAABAB, 0xCFD0D0, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xA3A4A4, 0xB9BABA, 0xDBDBDB, 0xF2F2F2, 0xF2F2F2, 0xDBDBDB, 0xB9BABA, 0xA3A4A4, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xEDEDEE, 0xC6C9CD, 0xB5BABF, 0xB5BABF, 0xC8CBCE, 0xEDEEEE, 0xC3C3C3, 0xA2A3A3, 0xFFFFFF}, + {0xCFD0D0, 0xB9BABA, 0xE9EAEB, 0xB3B8BD, 0xBDC2C7, 0xC8CDD2, 0xC9CED3, 0xC5C8CC, 0xBEC1C5, 0xEBECEC, 0xB9BABA, 0xCFD0D0}, + {0xA9A9A9, 0xDCDCDC, 0xC5C8CC, 0xBEC3C9, 0xCBCFD5, 0xCED2D7, 0xD5D8DC, 0xDCDEE0, 0xD3D4D7, 0xD4D5D5, 0xDCDCDC, 0xA9A9A9}, + {0x919292, 0xF2F2F2, 0xB4B9BD, 0xCDD1D6, 0xD3D6DA, 0xDBDDDF, 0xE4E4E5, 0xE9E9E9, 0xE8E8E9, 0xD0D1D2, 0xF2F2F2, 0x919292}, + {0x919292, 0xF2F2F2, 0xBBBEC2, 0xD7DADD, 0xE0E1E3, 0xE9E9E9, 0xEFEFEF, 0xF0F0F0, 0xEFEFF0, 0xDBDCDC, 0xEFEFEF, 0x939494}, + {0xA7A8A8, 0xDDDDDD, 0xCFD1D3, 0xD5D6D8, 0xE9E9E9, 0xEFEFEF, 0xF4F4F4, 0xF5F5F5, 0xEEEEEE, 0xE8E8E8, 0xDDDDDD, 0xA7A8A8}, + {0xCECECE, 0xBABBBB, 0xECECED, 0xCDCECF, 0xE1E2E2, 0xF0F0F0, 0xF4F4F4, 0xF1F1F1, 0xEBEBEB, 0xF2F2F2, 0xBABBBB, 0xCECECE}, + {0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xF0F0F1, 0xE2E3E3, 0xE4E4E5, 0xE9EAEA, 0xEEEEEF, 0xF3F3F3, 0xC3C3C3, 0xA2A3A3, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xA2A3A3, 0xBABBBB, 0xDBDBDB, 0xF4F4F4, 0xF4F4F4, 0xDCDCDC, 0xBABBBB, 0xA2A3A3, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCECECE, 0xAAABAB, 0x8E8F8F, 0x8E8F8F, 0xA9A9A9, 0xCECECE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF} + }; + unsigned bmp_unchecked_highlight[12][12] = { + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB7CCD8, 0x7FA4BA, 0x5989A5, 0x5989A5, 0x7FA4BA, 0xB7CCD8, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0x759DB4, 0x8FB7C8, 0xBCDDE5, 0xDBF6F8, 0xDBF6F8, 0xBCDDE5, 0x8FB7C8, 0x759DB4, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD3F4FA, 0x9BD7F9, 0x84CBF9, 0x84CBF9, 0x9CD8F9, 0xD4F4FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF}, + {0xB7CCD8, 0x8FB7C8, 0xCFF1FA, 0x80CAF9, 0x96D3FB, 0xAADDFD, 0xABDDFD, 0x9AD5FB, 0x86CEF9, 0xCFF2FA, 0x8FB7C8, 0xB7CCD8}, + {0x7DA2B9, 0xBEDEE6, 0x9AD7F9, 0x98D5FB, 0xB1DFFD, 0xB2E0FD, 0xB7E3FD, 0xBCE5FD, 0xA6DCFB, 0xA1DCF9, 0xBEDEE6, 0x7DA2B9}, + {0x5989A5, 0xDBF6F8, 0x80CAF9, 0xAFDEFD, 0xB6E2FD, 0xBBE5FD, 0xC1E8FD, 0xC5EAFD, 0xC7EBFD, 0x99D8FA, 0xDBF6F8, 0x5989A5}, + {0x5989A5, 0xDBF6F8, 0x84CDF9, 0xB6E2FD, 0xBFE7FD, 0xC7EBFD, 0xD5F0FE, 0xDAF2FE, 0xD8F1FE, 0xB1E1FB, 0xD8F4F6, 0x5D8CA7}, + {0x7BA1B8, 0xBFDFE7, 0x9FDBF9, 0xA7DDFB, 0xC8EBFD, 0xD6F1FE, 0xE2F5FE, 0xE5F6FE, 0xD8F0FD, 0xCAEDFB, 0xBFDFE7, 0x7BA1B8}, + {0xB5CAD7, 0x91B8C9, 0xCFF2FA, 0x92D5F9, 0xBAE5FC, 0xDAF2FE, 0xE4F5FE, 0xDFF3FE, 0xD2EEFD, 0xDBF7FA, 0x91B8C9, 0xB5CAD7}, + {0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD7F6FA, 0xBDE8FB, 0xC2E8FC, 0xD0EDFD, 0xD7F2FC, 0xDDF8FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0x739BB3, 0x91B8C9, 0xBCDDE5, 0xDEF9FA, 0xDEF9FA, 0xBEDEE6, 0x91B8C9, 0x739BB3, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB5CAD7, 0x7FA4BA, 0x5586A3, 0x5586A3, 0x7DA2B9, 0xB5CAD7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF} + }; + unsigned bmp_checked[12][12] = { + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCFD0D0, 0xAAABAB, 0x919292, 0x919292, 0xAAABAB, 0xCFD0D0, 0xFCFCFC, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xA3A4A4, 0xB9BABA, 0xDBDBDB, 0xF2F2F2, 0xF2F2F2, 0xDBDBDB, 0xB9BABA, 0xA3A4A4, 0xF3F3F3, 0xFFFFFF}, + {0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xEDEDEE, 0xBABFC5, 0x85939F, 0x85939F, 0xBCC1C5, 0xEDEEEE, 0xC3C3C3, 0xA2A3A3, 0xFCFCFC}, + {0xCFD0D0, 0xB9BABA, 0xE9EAEB, 0x8997A2, 0x274760, 0x486378, 0x365166, 0x204058, 0x8E9AA4, 0xEBECEC, 0xB9BABA, 0xCFD0D0}, + {0xA9A9A9, 0xDCDCDC, 0xB9BEC4, 0x24445D, 0x91B2C6, 0xC7EBFD, 0x69C2D4, 0x14405C, 0x1E3F57, 0xC9CCCD, 0xDCDCDC, 0xA9A9A9}, + {0x919292, 0xF2F2F2, 0x7D8D98, 0x304B5F, 0x90D5E5, 0x5DCEDD, 0x28A2D1, 0x178AC7, 0x183348, 0x8F9CA6, 0xF2F2F2, 0x919292}, + {0x919292, 0xF2F2F2, 0x82909C, 0x183347, 0x228FC6, 0x209DD1, 0x1898D1, 0x0E84C6, 0x183348, 0x97A3AC, 0xEFEFEF, 0x939494}, + {0xA7A8A8, 0xDDDDDD, 0xC0C5C9, 0x1E3F57, 0x0F3F5D, 0x0F83C7, 0x0B82C7, 0x0C3D5D, 0x1F3F58, 0xD9DCDE, 0xDDDDDD, 0xA7A8A8}, + {0xCECECE, 0xBABBBB, 0xECECED, 0x99A3AB, 0x1D3E57, 0x18354A, 0x19344A, 0x1E3E57, 0xAEB8BF, 0xF2F2F2, 0xBABBBB, 0xCECECE}, + {0xFFFFFF, 0xA2A3A3, 0xC3C3C3, 0xF0F0F1, 0xD1D5D7, 0xA6B0B9, 0xA9B4BC, 0xDCDFE2, 0xF3F3F3, 0xC3C3C3, 0xA2A3A3, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xA2A3A3, 0xBABBBB, 0xDBDBDB, 0xF4F4F4, 0xF4F4F4, 0xDCDCDC, 0xBABBBB, 0xA2A3A3, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCECECE, 0xAAABAB, 0x8E8F8F, 0x8E8F8F, 0xA9A9A9, 0xCECECE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF} + }; + + unsigned bmp_checked_highlight[12][12] = { + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB7CCD8, 0x7FA4BA, 0x5989A5, 0x5989A5, 0x7FA4BA, 0xB7CCD8, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0x759DB4, 0x8FB7C8, 0xBCDDE5, 0xDBF6F8, 0xDBF6F8, 0xBCDDE5, 0x8FB7C8, 0x759DB4, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD3F4FA, 0x92CCED, 0x639FC7, 0x639FC7, 0x93CDED, 0xD4F4FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF}, + {0xB7CCD8, 0x8FB7C8, 0xCFF1FA, 0x66A3CC, 0x264862, 0x47647A, 0x355268, 0x1E405A, 0x66A3C9, 0xCFF2FA, 0x8FB7C8, 0xB7CCD8}, + {0x7DA2B9, 0xBEDEE6, 0x91CCED, 0x22445E, 0x9DBBCD, 0xE9F7FE, 0x7FE6EE, 0x154664, 0x1D3F58, 0x99D3EF, 0xBEDEE6, 0x7DA2B9}, + {0x5989A5, 0xDBF6F8, 0x5C98BF, 0x2F4B60, 0xB1F6FA, 0x74FFFF, 0x32CAFF, 0x1DAAF3, 0x173348, 0x6CA1C0, 0xDBF6F8, 0x5989A5}, + {0x5989A5, 0xDBF6F8, 0x5E99BF, 0x173348, 0x2AB0F2, 0x28C4FF, 0x1EBEFF, 0x11A3F2, 0x173348, 0x7BA6C0, 0xD8F4F6, 0x5D8CA7}, + {0x7BA1B8, 0xBFDFE7, 0x94CEEB, 0x1D3F58, 0x114567, 0x13A2F3, 0x0DA0F3, 0x0D4367, 0x1E3F58, 0xBEE0EF, 0xBFDFE7, 0x7BA1B8}, + {0xB5CAD7, 0x91B8C9, 0xCFF2FA, 0x6FA8C9, 0x1C3E58, 0x18354B, 0x18354B, 0x1D3E58, 0x9CBACC, 0xDBF7FA, 0x91B8C9, 0xB5CAD7}, + {0xFFFFFF, 0x739BB3, 0x9CC2D0, 0xD7F6FA, 0xAFDAED, 0x8EB3C9, 0x98B7CA, 0xC7E3EE, 0xDDF8FA, 0x9CC2D0, 0x739BB3, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0x739BB3, 0x91B8C9, 0xBCDDE5, 0xDEF9FA, 0xDEF9FA, 0xBEDEE6, 0x91B8C9, 0x739BB3, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xB5CAD7, 0x7FA4BA, 0x5586A3, 0x5586A3, 0x7DA2B9, 0xB5CAD7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF} + }; + + unsigned bmp_checked_press[12][12] = { + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xA6BDCE, 0x6089A8, 0x31668E, 0x31668E, 0x6089A8, 0xA6BDCE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0x5480A1, 0x6C99B8, 0x9DC4DC, 0xBEE1F3, 0xBEE1F3, 0x9DC4DC, 0x6C99B8, 0x5480A1, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0x517E9F, 0x7AA5C2, 0xB6DDF3, 0x73B2D6, 0x4A8AB0, 0x4A8AB0, 0x74B3D8, 0xB7DEF3, 0x7AA5C2, 0x517E9F, 0xFFFFFF}, + {0xA6BDCE, 0x6C99B8, 0xB1DBF1, 0x4B8DB4, 0x244660, 0x456279, 0x335167, 0x1D3F59, 0x4C90B7, 0xB1DCF3, 0x6C99B8, 0xA6BDCE}, + {0x5E87A6, 0x9FC5DD, 0x71B1D6, 0x21435D, 0x7EA5BC, 0x95D9FC, 0x478BAE, 0x113858, 0x1B3E58, 0x78BDE2, 0x9FC5DD, 0x5E87A6}, + {0x31668E, 0xBEE1F3, 0x4484AA, 0x2E4A60, 0x5DA2C6, 0x3A84AA, 0x19658D, 0x0F5984, 0x153248, 0x5794B7, 0xBEE1F3, 0x31668E}, + {0x31668E, 0xBEE1F3, 0x4687AE, 0x153247, 0x165D84, 0x14628D, 0x0F5F8D, 0x095684, 0x163248, 0x6B9DB9, 0xBBDEF1, 0x366990}, + {0x5B85A5, 0xA0C7DE, 0x74B7DC, 0x1B3E58, 0x0D3659, 0x0A5583, 0x075483, 0x0A3459, 0x1E3F58, 0xA9D2E9, 0xA0C7DE, 0x5B85A5}, + {0xA3BBCD, 0x6D9BBA, 0xB2DDF3, 0x5599BE, 0x1C3E57, 0x17344A, 0x17344B, 0x1D3E57, 0x91B3C7, 0xC1E4F6, 0x6D9BBA, 0xA3BBCD}, + {0xFFFFFF, 0x517E9F, 0x7AA5C2, 0xBBE1F5, 0x98CAE4, 0x80AAC3, 0x8CAFC5, 0xB7D7EA, 0xC2E4F6, 0x7AA5C2, 0x517E9F, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0x517E9F, 0x6D9BBA, 0x9DC4DC, 0xC2E4F6, 0xC2E4F6, 0x9FC5DD, 0x6D9BBA, 0x517E9F, 0xFFFFFF, 0xFFFFFF}, + {0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xA3BBCD, 0x6089A8, 0x2C628B, 0x2C628B, 0x5E87A6, 0xA3BBCD, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF} + }; + + unsigned (*colormap)[12][12] = &bmp_unchecked; + + switch(es) + { + case element_state::normal: + case element_state::focus_normal: + colormap = (crook_data.check_state != state::unchecked ? &bmp_checked : &bmp_unchecked); + break; + case element_state::hovered: + case element_state::focus_hovered: + colormap = (crook_data.check_state != state::unchecked ? &bmp_checked_highlight : &bmp_unchecked_highlight); + break; + case element_state::pressed: + colormap = &bmp_checked_press; + break; + default: + break; + } + + const int x = r.x + 2; + const int y = r.y + 2; + + for(int top = 0; top < 12; ++top) + { + for(int left = 0; left < 12; ++left) + { + if((*colormap)[top][left] != 0xFFFFFF) + graph.set_pixel(left + x, top + y, (*colormap)[top][left]); + } + } + } + else + { + const nana::color_t highlighted = 0x5EB6F7; + + switch(es) + { + case element_state::hovered: + case element_state::focus_hovered: + bgcolor = graph.mix(bgcolor, highlighted, 0.8); + fgcolor = graph.mix(fgcolor, highlighted, 0.8); + break; + case element_state::pressed: + bgcolor = graph.mix(bgcolor, highlighted, 0.4); + fgcolor = graph.mix(fgcolor, highlighted, 0.4); + break; + case element_state::disabled: + bgcolor = fgcolor = 0xB2B7BC; + break; + default: + //Leave things as they are + break; + } + const int x = r.x + 1; + const int y = r.y + 1; + + graph.rectangle(x, y, 13, 13, fgcolor, false); + graph.rectangle(x + 1, y + 1, 11, 11, bgcolor, true); + + switch(crook_data.check_state) + { + case state::checked: + { + int sx = x + 2; + int sy = y + 4; + + for(int i = 0; i < 3; i++) + { + sx++; + sy++; + graph.line(sx, sy, sx, sy + 3, fgcolor); + } + + for(int i = 0; i < 4; i++) + { + sx++; + sy--; + graph.line(sx, sy, sx, sy + 3, fgcolor); + } + } + break; + case state::partial: + graph.rectangle(x + 2, y + 2, 9, 9, fgcolor, true); + break; + default: + break; + } + } + return true; + } + }; //end class crook + + class menu_crook + : public crook_interface + { + bool draw(graph_reference graph, nana::color_t, nana::color_t fgcolor, const nana::rectangle& r, element_state es, const data& crook_data) override + { + if(crook_data.check_state == state::unchecked) + return true; + + if(crook_data.radio) + { + unsigned colormap[8][8] = { + {0xFF000000,0xdee7ef,0x737baa,0x232674,0x3c3f84,0x8d96ba,0xe0e9ef,0xFF000000}, + {0xdce4ed,0x242875,0x6f71b3,0x9fa0d6,0xc3c4e9,0xb1b2da,0x5c6098,0xdbe4ed}, + {0x7b81ad,0x4f5199,0x8182c1,0xa1a2d4,0xccccea,0xcccced,0x9c9dcf,0x7981ae}, + {0x2b2d77,0x4f509a,0x696baf,0x7879ba,0xa4a6d4,0xa9aad9,0x9193ce,0x1e2271}, + {0x36387f,0x383a87,0x52549c,0x6162a8,0x6f71b3,0x7e7fbf,0x7879ba,0x282c78}, + {0x9094ba,0x1b1c71,0x3c3e8b,0x4a4b96,0x585aa1,0x6768ac,0x464893,0x828bb6}, + {0xe2eaf1,0x4b4d8d,0x16186d,0x292b7c,0x333584,0x2c2e7f,0x454b8c,0xdfe9f0}, + {0xFF000000,0xe4ecf2,0x9599bd,0x454688,0x414386,0x9095bb,0xe3ebf2,0xFF000000} + }; + + int x = r.x + (static_cast(r.width) - 8) / 2; + int y = r.y + (static_cast(r.height) - 8) / 2; + + for(int u = 0; u < 8; ++u) + { + for(int v = 0; v < 8; ++v) + { + if(colormap[u][v] & 0xFF000000) + continue; + graph.set_pixel(x + v, y, colormap[u][v]); + } + ++y; + } + } + else + { + int x = r.x + (static_cast(r.width) - 16) / 2; + int y = r.y + (static_cast(r.height) - 16) / 2; + + nana::color_t light = graph.mix(fgcolor, 0xFFFFFF, 0.5); + + graph.line(x + 3, y + 7, x + 6, y + 10, fgcolor); + graph.line(x + 7, y + 9, x + 12, y + 4, fgcolor); + graph.line(x + 3, y + 8, x + 6, y + 11, light); + graph.line(x + 7, y + 10, x + 12, y + 5, light); + graph.line(x + 4, y + 7, x + 6, y + 9, light); + graph.line(x + 7, y + 8, x + 11, y + 4, light); + } + return true; + } + }; + } + + template + class element_object + : nana::noncopyable, nana::nonmovable + { + typedef ElementInterface element_t; + typedef pat::cloneable> factory_interface; + + public: + element_object() + : element_ptr_(nullptr) + { + } + + ~element_object() + { + if(factory_) + factory_->destroy(element_ptr_); + } + + void push(const factory_interface& rhs) + { + auto keep_f = factory_; + auto keep_e = element_ptr_; + + factory_ = rhs; + element_ptr_ = factory_->create(); + + if(nullptr == factory_ || nullptr == element_ptr_) + { + if(element_ptr_) + factory_->destroy(element_ptr_); + + factory_.reset(); + + factory_ = keep_f; + element_ptr_ = keep_e; + } + else + spare_.emplace_back(keep_e, keep_f); + } + + element_t * const * keeper() const + { + return &element_ptr_; + } + private: + factory_interface factory_; //Keep the factory for destroying the element + element_t * element_ptr_; + std::vector> spare_; + }; + + class element_manager + : nana::noncopyable, nana::nonmovable + { + //VC2012 does not support alias declaration. + //template using factory_interface = element::provider::factory_interface; + + template + struct item + { + element_object * employee; + std::map>> table; + }; + + element_manager() + { + crook_.employee = nullptr; + } + + public: + static element_manager& instance() + { + static bool initial = true; + static element_manager obj; + if(initial) + { + initial = false; + + element::add_crook(""); + element::add_crook("menu_crook"); + } + return obj; + } + + void crook(const std::string& name, const pat::cloneable>& factory) + { + _m_add(name, crook_, factory); + } + + element::crook_interface * const * crook(const std::string& name) const + { + return _m_get(name, crook_).keeper(); + } + private: + typedef std::lock_guard lock_guard; + + template + void _m_add(const std::string& name, item& m, const pat::cloneable>& factory) + { + typedef element_object element_object_t; + lock_guard lock(mutex_); + + auto & eop = m.table[name]; + if(nullptr == eop) + eop = std::make_shared(); + + eop->push(factory); + if(nullptr == m.employee) + m.employee = eop.get(); + } + + template + const element_object& _m_get(const std::string& name, const item& m) const + { + lock_guard lock(mutex_); + + auto i = m.table.find(name); + if(i != m.table.end()) + return *(i->second); + + return *m.employee; + } + + private: + mutable std::recursive_mutex mutex_; + item crook_; + }; + + namespace element + { + //class provider + void provider::add_crook(const std::string& name, const pat::cloneable>& factory) + { + element_manager::instance().crook(name, factory); + } + + crook_interface* const * provider::keeper_crook(const std::string& name) + { + return element_manager::instance().crook(name); + } + }//end namespace element + + //facades + //template<> class facade + facade::facade() + : keeper_(element::provider().keeper_crook("")) + { + data_.check_state = state::unchecked; + data_.radio = false; + } + + facade::facade(const char* name) + : keeper_(element::provider().keeper_crook(name ? name : "")) + { + data_.check_state = state::unchecked; + data_.radio = false; + } + + facade & facade::reverse() + { + data_.check_state = (data_.check_state == facade::state::unchecked ? facade::state::checked : facade::state::unchecked); + return *this; + } + + facade & facade::check(state s) + { + data_.check_state = s; + return *this; + } + + facade::state facade::checked() const + { + return data_.check_state; + } + + facade & facade::radio(bool r) + { + data_.radio = r; + return *this; + } + + bool facade::radio() const + { + return data_.radio; + } + + void facade::switch_to(const char* name) + { + keeper_ = element::provider().keeper_crook(name); + } + + bool facade::draw(graph_reference graph, nana::color_t bgcol, nana::color_t fgcol, const nana::rectangle& r, element_state es) + { + return (*keeper_)->draw(graph, bgcol, fgcol, r, es, data_); + } + //end class facade + + namespace element + { + void set_bground(const char* name, const pat::cloneable& obj) + { + detail::bedrock::instance().get_element_store().bground(name, obj); + } + + void set_bground(const char* name, pat::cloneable && obj) + { + detail::bedrock::instance().get_element_store().bground(name, std::move(obj)); + } + + //class cite + cite_bground::cite_bground(const char* name) + : ref_ptr_(detail::bedrock::instance().get_element_store().bground(name)) + { + } + + void cite_bground::set(const cloneable_element& rhs) + { + holder_ = rhs; + place_ptr_ = holder_.get(); + ref_ptr_ = &place_ptr_; + } + + void cite_bground::set(const char* name) + { + holder_.reset(); + ref_ptr_ = detail::bedrock::instance().get_element_store().bground(name); + } + + bool cite_bground::draw(graph_reference dst, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& r, element_state state) + { + if (ref_ptr_ && *ref_ptr_) + return (*ref_ptr_)->draw(dst, bgcolor, fgcolor, r, state); + + return false; + } + //end class cite + + //class bground + struct bground::draw_method + { + virtual ~draw_method(){} + + virtual draw_method * clone() const = 0; + + virtual void paste(const nana::rectangle& from_r, graph_reference, const nana::point& dst_pos) = 0; + virtual void stretch(const nana::rectangle& from_r, graph_reference dst, const nana::rectangle & to_r) = 0; + }; + + struct bground::draw_image + : public draw_method + { + nana::paint::image image; + + draw_image(const nana::paint::image& img) + : image(img) + {} + + draw_method * clone() const override + { + return new draw_image(image); + } + + void paste(const nana::rectangle& from_r, graph_reference dst, const nana::point& dst_pos) override + { + image.paste(from_r, dst, dst_pos); + } + + void stretch(const nana::rectangle& from_r, graph_reference dst, const nana::rectangle& to_r) override + { + image.stretch(from_r, dst, to_r); + } + }; + + struct bground::draw_graph + : public draw_method + { + nana::paint::graphics graph; + + draw_graph() + {} + + draw_graph(const nana::paint::graphics& g) + : graph(g) + {} + + draw_method * clone() const override + { + auto p = new draw_graph; + p->graph.make(graph.width(), graph.height()); + graph.paste(p->graph, 0, 0); + return p; + } + + void paste(const nana::rectangle& from_r, graph_reference dst, const nana::point& dst_pos) override + { + graph.paste(from_r, dst, dst_pos.x, dst_pos.y); + } + + void stretch(const nana::rectangle& from_r, graph_reference dst, const nana::rectangle& to_r) override + { + graph.stretch(from_r, dst, to_r); + } + }; + + bground::bground() + : method_(nullptr), + vertical_(false), + stretch_all_(true), + left_(0), top_(0), right_(0), bottom_(0) + { + reset_states(); + } + + bground::bground(const bground& rhs) + : method_(rhs.method_ ? rhs.method_->clone() : nullptr), + vertical_(rhs.vertical_), + valid_area_(rhs.valid_area_), + states_(rhs.states_), + join_(rhs.join_), + stretch_all_(rhs.stretch_all_), + left_(rhs.left_), top_(rhs.top_), right_(rhs.right_), bottom_(rhs.bottom_) + { + } + + bground::~bground() + { + delete method_; + } + + bground& bground::operator=(const bground& rhs) + { + if (this != &rhs) + { + delete method_; + method_ = (rhs.method_ ? rhs.method_->clone() : nullptr); + vertical_ = rhs.vertical_; + valid_area_ = rhs.valid_area_; + states_ = rhs.states_; + join_ = rhs.join_; + stretch_all_ = rhs.stretch_all_; + left_ = rhs.left_; + top_ = rhs.top_; + right_ = rhs.right_; + bottom_ = rhs.bottom_; + } + return *this; + } + + //Set a picture for the background + bground& bground::image(const paint::image& img, bool vertical, const nana::rectangle& valid_area) + { + delete method_; + method_ = new draw_image(img); + vertical_ = vertical; + + if (valid_area.width && valid_area.height) + valid_area_ = valid_area; + else + valid_area_ = nana::rectangle(img.size()); + return *this; + } + + bground& bground::image(const paint::graphics& graph, bool vertical, const nana::rectangle& valid_area) + { + delete method_; + method_ = new draw_graph(graph); + vertical_ = vertical; + + if (valid_area.width && valid_area.height) + valid_area_ = valid_area; + else + valid_area_ = nana::rectangle(graph.size()); + return *this; + } + + //Set the state sequence of the background picture. + void bground::states(const std::vector & s) + { + states_ = s; + } + + void bground::states(std::vector && s) + { + states_ = std::move(s); + } + + void bground::reset_states() + { + states_.clear(); + states_.push_back(element_state::normal); + states_.push_back(element_state::hovered); + states_.push_back(element_state::focus_normal); + states_.push_back(element_state::focus_hovered); + states_.push_back(element_state::pressed); + states_.push_back(element_state::disabled); + join_.clear(); + } + + void bground::join(element_state target, element_state joiner) + { + join_[joiner] = target; + } + + void bground::stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom) + { + left_ = left; + top_ = top; + right_ = right; + bottom_ = bottom; + + stretch_all_ = !(left || right || top || bottom); + } + + //Implement the methods of bground_interface. + bool bground::draw(graph_reference dst, nana::color_t bgcolor, nana::color_t fgcolor, const nana::rectangle& to_r, element_state state) + { + if (nullptr == method_) + return false; + + auto mi = join_.find(state); + if (mi != join_.end()) + state = mi->second; + + std::size_t pos = 0; + for (; pos < states_.size(); ++pos) + { + if (states_[pos] == state) + break; + } + + if (pos == states_.size()) + return false; + + nana::rectangle from_r = valid_area_; + if (vertical_) + { + from_r.height /= static_cast(states_.size()); + from_r.y += static_cast(from_r.height * pos); + } + else + { + from_r.width /= static_cast(states_.size()); + from_r.x += static_cast(from_r.width * pos); + } + + if (stretch_all_) + { + if (from_r.width == to_r.width && from_r.height == to_r.height) + method_->paste(from_r, dst, to_r); + else + method_->stretch(from_r, dst, to_r); + + return true; + } + + + auto perf_from_r = from_r; + auto perf_to_r = to_r; + + if (left_ + right_ < to_r.width) + { + nana::rectangle src_r = from_r; + src_r.y += static_cast(top_); + src_r.height -= top_ + bottom_; + + nana::rectangle dst_r = to_r; + dst_r.y += static_cast(top_); + dst_r.height -= top_ + bottom_; + + if (left_) + { + src_r.width = left_; + dst_r.width = left_; + + method_->stretch(src_r, dst, dst_r); + + perf_from_r.x += static_cast(left_); + perf_from_r.width -= left_; + perf_to_r.x += static_cast(left_); + perf_to_r.width -= left_; + } + + if (right_) + { + src_r.x += (static_cast(from_r.width) - static_cast(right_)); + src_r.width = right_; + + dst_r.x += (static_cast(to_r.width) - static_cast(right_)); + dst_r.width = right_; + + method_->stretch(src_r, dst, dst_r); + + perf_from_r.width -= right_; + perf_to_r.width -= right_; + } + } + + if (top_ + bottom_ < to_r.height) + { + nana::rectangle src_r = from_r; + src_r.x += static_cast(left_); + src_r.width -= left_ + right_; + + nana::rectangle dst_r = to_r; + dst_r.x += static_cast(left_); + dst_r.width -= left_ + right_; + + if (top_) + { + src_r.height = top_; + dst_r.height = top_; + + method_->stretch(src_r, dst, dst_r); + + perf_from_r.y += static_cast(top_); + perf_to_r.y += static_cast(top_); + } + + if (bottom_) + { + src_r.y += static_cast(from_r.height - bottom_); + src_r.height = bottom_; + + dst_r.y += static_cast(to_r.height - bottom_); + dst_r.height = bottom_; + + method_->stretch(src_r, dst, dst_r); + } + + perf_from_r.height -= (top_ + bottom_); + perf_to_r.height -= (top_ + bottom_); + } + + if (left_) + { + nana::rectangle src_r = from_r; + src_r.width = left_; + if (top_) + { + src_r.height = top_; + method_->paste(src_r, dst, to_r); + } + if (bottom_) + { + src_r.y += static_cast(from_r.height) - static_cast(bottom_); + src_r.height = bottom_; + method_->paste(src_r, dst, nana::point(to_r.x, to_r.y + static_cast(to_r.height - bottom_))); + } + } + + if (right_) + { + const int to_x = to_r.x + int(to_r.width - right_); + + nana::rectangle src_r = from_r; + src_r.x += static_cast(src_r.width) - static_cast(right_); + src_r.width = right_; + if (top_) + { + src_r.height = top_; + method_->paste(src_r, dst, nana::point(to_x, to_r.y)); + } + if (bottom_) + { + src_r.y += (static_cast(from_r.height) - static_cast(bottom_)); + src_r.height = bottom_; + method_->paste(src_r, dst, nana::point(to_x, to_r.y + int(to_r.height - bottom_))); + } + } + + method_->stretch(perf_from_r, dst, perf_to_r); + return true; + } + //end class bground + }//end namespace element +}//end namespace nana diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp new file mode 100644 index 00000000..46ca0a59 --- /dev/null +++ b/source/gui/filebox.cpp @@ -0,0 +1,1011 @@ +#include +#include + +#if defined(NANA_WINDOWS) + #include +#elif defined(NANA_LINUX) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace nana +{ +#if defined(NANA_LINUX) + class filebox_implement + : public form + { + struct item_fs + { + nana::string name; + ::tm modified_time; + bool directory; + nana::long_long_t bytes; + + friend listbox::iresolver& operator>>(listbox::iresolver& ires, item_fs& m) + { + nana::string type; + ires>>m.name>>type>>type; + m.directory = (type == STR("Directory")); + return ires; + } + + friend listbox::oresolver& operator<<(listbox::oresolver& ores, const item_fs& item) + { + std::wstringstream tm; + tm<<(item.modified_time.tm_year + 1900)<<'-'; + _m_add(tm, item.modified_time.tm_mon + 1)<<'-'; + _m_add(tm, item.modified_time.tm_mday)<<' '; + + _m_add(tm, item.modified_time.tm_hour)<<':'; + _m_add(tm, item.modified_time.tm_min)<<':'; + _m_add(tm, item.modified_time.tm_sec); + + ores<= 1024) + { + double cap = bytes / 1024.0; + std::size_t uid = 0; + while((cap >= 1024.0) && (uid < (sizeof(ustr) / sizeof(nana::char_t*)))) + { + cap /= 1024.0; + ++uid; + } + ss<(nana::charset(s)) + ustr[uid]; + } + ss<&) + { + auto path = path_.caption(); + auto root = path.substr(0, path.find(STR('/'))); + if(root == STR("HOME")) + path.replace(0, 4, nana::filesystem::path_user()); + else if(root == STR("FILESYSTEM")) + path.erase(0, 10); + else + throw std::runtime_error("Nana.GUI.Filebox: Wrong categorize path"); + + if(path.size() == 0) path = STR("/"); + _m_load_cat_path(path); + }); + + filter_.create(*this); + filter_.multi_lines(false); + filter_.tip_string(STR("Filter")); + + filter_.events().key_release([this](const arg_keyboard&) + { + _m_list_fs(); + }); + + btn_folder_.create(*this); + btn_folder_.caption(STR("&New Folder")); + + btn_folder_.events().click([this](const arg_mouse&) + { + form fm(this->handle(), API::make_center(*this, 300, 35)); + fm.caption(STR("Name the new folder")); + + textbox folder(fm, nana::rectangle(5, 5, 160, 25)); + folder.multi_lines(false); + + button btn(fm, nana::rectangle(170, 5, 60, 25)); + btn.caption(STR("Create")); + + btn.events().click(folder_creator(*this, fm, folder)); + + button btn_cancel(fm, nana::rectangle(235, 5, 60, 25)); + btn_cancel.caption(STR("Cancel")); + + btn_cancel.events().click([&fm](const arg_mouse&) + { + fm.close(); + }); + API::modal_window(fm); + }); + + tree_.create(*this); + + ls_file_.create(*this); + ls_file_.append_header(STR("Name"), 190); + ls_file_.append_header(STR("Modified"), 145); + ls_file_.append_header(STR("Type"), 80); + ls_file_.append_header(STR("Size"), 70); + + auto fn_sel_file = [this](const arg_mouse& arg){ + _m_sel_file(arg); + }; + ls_file_.events().dbl_click(fn_sel_file); + ls_file_.events().mouse_down(fn_sel_file); + ls_file_.set_sort_compare(0, [](const nana::string& a, nana::any* fs_a, const nana::string& b, nana::any* fs_b, bool reverse) -> bool + { + int dira = fs_a->get()->directory ? 1 : 0; + int dirb = fs_b->get()->directory ? 1 : 0; + if(dira != dirb) + return (reverse ? dira < dirb : dira > dirb); + + std::size_t seek_a = 0; + std::size_t seek_b = 0; + + while(true) + { + std::size_t pos_a = a.find_first_of(STR("0123456789"), seek_a); + std::size_t pos_b = b.find_first_of(STR("0123456789"), seek_b); + + if((pos_a != a.npos) && (pos_a == pos_b)) + { + nana::cistring text_a = a.substr(seek_a, pos_a - seek_a).data(); + nana::cistring text_b = b.substr(seek_b, pos_b - seek_b).data(); + + if(text_a != text_b) + return (reverse ? text_a > text_b : text_a < text_b); + + std::size_t end_a = a.find_first_not_of(STR("0123456789"), pos_a + 1); + std::size_t end_b = b.find_first_not_of(STR("0123456789"), pos_b + 1); + + nana::string num_a = a.substr(pos_a, end_a != a.npos ? end_a - pos_a : a.npos); + nana::string num_b = b.substr(pos_b, end_b != b.npos ? end_b - pos_b : b.npos); + + if(num_a != num_b) + { + double ai = std::stod(num_a, 0); + double bi = std::stod(num_b, 0); + if(ai != bi) + return (reverse ? ai > bi : ai < bi); + } + + seek_a = end_a; + seek_b = end_b; + } + else + break; + } + if(seek_a == a.npos) + seek_a = 0; + if(seek_b == b.npos) + seek_b = 0; + + nana::cistring cia = a.data(); + nana::cistring cib = b.data(); + if(seek_a == seek_b && seek_a == 0) + return (reverse ? cia > cib : cia < cib); + return (reverse ? cia.substr(seek_a) > cib.substr(seek_b) : cia.substr(seek_a) < cib.substr(seek_b)); + }); + ls_file_.set_sort_compare(2, [](const nana::string& a, nana::any* anyptr_a, const nana::string& b, nana::any* anyptr_b, bool reverse) -> bool + { + int dir1 = anyptr_a->get()->directory ? 1 : 0; + int dir2 = anyptr_b->get()->directory ? 1 : 0; + if(dir1 != dir2) + return (reverse ? dir1 < dir2 : dir1 > dir2); + + return (reverse ? a > b : a < b); + }); + ls_file_.set_sort_compare(3, [this](const nana::string&, nana::any* anyptr_a, const nana::string&, nana::any* anyptr_b, bool reverse) -> bool + { + item_fs * fsa = anyptr_a->get(); + item_fs * fsb = anyptr_b->get(); + return (reverse ? fsa->bytes > fsb->bytes : fsa->bytes < fsb->bytes); + }); + + lb_file_.create(*this); + lb_file_.caption(STR("File:")); + + tb_file_.create(*this); + tb_file_.multi_lines(false); + + tb_file_.events().key_char([this](const arg_keyboard& arg) + { + if(arg.key == nana::keyboard::enter) + _m_ok(); + }); + + cb_types_.create(*this); + cb_types_.editable(false); + cb_types_.events().selected([this](const arg_combox&){ _m_list_fs(); }); + + btn_ok_.create(*this); + btn_ok_.caption(STR("&OK")); + + btn_ok_.events().click([this](const arg_mouse&) + { + _m_ok(); + }); + btn_cancel_.create(*this); + btn_cancel_.caption(STR("&Cancel")); + + btn_cancel_.events().click([this](const arg_mouse&) + { + API::close_window(handle()); + }); + + selection_.type = kind::none; + _m_layout(); + _m_init_tree(); + + if(0 == title.size()) + caption(io_read ? STR("Open") : STR("Save As")); + else + caption(title); + } + + void def_extension(const nana::string& ext) + { + def_ext_ = ext; + } + + void load_fs(const nana::string& init_path, const nana::string& init_file) + { + //Simulate the behavior like Windows7's lpstrInitialDir(http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839%28v=vs.85%29.aspx) + + //Phase 1 + nana::string dir; + + auto pos = init_file.find_last_of(STR("\\/")); + nana::string file_with_path_removed = (pos != init_file.npos ? init_file.substr(pos + 1) : init_file); + + if(saved_init_path != init_path) + { + if(saved_init_path.size() == 0) + saved_init_path = init_path; + + //Phase 2: Check whether init_file contains a path + if(file_with_path_removed == init_file) + { + //Phase 3: Check whether init_path is empty + if(init_path.size()) + dir = init_path; + } + else + dir = init_file.substr(0, pos); + } + else + dir = saved_selected_path; + + _m_load_cat_path(dir.size() ? dir : nana::filesystem::path_user()); + + tb_file_.caption(file_with_path_removed); + } + + void add_filter(const nana::string& desc, const nana::string& type) + { + std::size_t i = cb_types_.the_number_of_options(); + cb_types_.push_back(desc); + if(0 == i) + cb_types_.option(0); + + std::vector v; + std::size_t beg = 0; + while(true) + { + auto pos = type.find(STR(';'), beg); + auto ext = type.substr(beg, pos == type.npos ? type.npos : pos - beg); + auto dot = ext.find(STR('.')); + if((dot != ext.npos) && (dot + 1 < ext.size())) + { + ext.erase(0, dot + 1); + if(ext == STR("*")) + { + v.clear(); + break; + } + else + v.push_back(ext); + } + if(pos == type.npos) + break; + beg = pos + 1; + } + if(v.size()) + cb_types_.anyobj(i, v); + } + + bool file(nana::string& fs) const + { + if(selection_.type == kind::none) + return false; + + auto pos = selection_.target.find_last_of(STR("\\/")); + if(pos != selection_.target.npos) + saved_selected_path = selection_.target.substr(0, pos); + else + saved_selected_path.clear(); + + fs = selection_.target; + return true; + } + private: + void _m_layout() + { + place_.bind(*this); + place_.div( "vert" + "" + "" + "" + "" + ">" + "" + ">"); + + place_.field("path")<directory) || (i->name.size() && i->name[0] == '.')) continue; + + item_proxy node = tree_.insert(nodes_.home, i->name, i->name); + if(false == node.empty()) + { + node.value(kind::filesystem); + break; + } + } + + for(file_iterator i(STR("/")); i != end; ++i) + { + if((false == i->directory) || (i->name.size() && i->name[0] == '.')) continue; + + item_proxy node = tree_.insert(nodes_.filesystem, i->name, i->name); + if(false == node.empty()) + { + node.value(kind::filesystem); + break; + } + } + + tree_.events().expanded([this](const arg_treebox& arg) + { + _m_tr_expand(arg.item, arg.operated); + }); + + tree_.events().selected([this](const arg_treebox& arg) + { + if(arg.operated && (arg.item.value() == kind::filesystem)) + { + auto path = tree_.make_key_path(arg.item, STR("/")) + STR("/"); + _m_resolute_path(path); + _m_load_cat_path(path); + } + }); + } + + nana::string _m_resolute_path(nana::string& path) + { + auto pos = path.find(STR('/')); + if(pos != path.npos) + { + auto begstr = path.substr(0, pos); + if(begstr == STR("FS.HOME")) + path.replace(0, 7, nana::filesystem::path_user()); + else + path.erase(0, pos); + return begstr; + } + return nana::string(); + } + + void _m_load_path(const nana::string& path) + { + addr_.filesystem = path; + if(addr_.filesystem.size() && addr_.filesystem[addr_.filesystem.size() - 1] != STR('/')) + addr_.filesystem += STR('/'); + + file_container_.clear(); + + using namespace nana::filesystem; + attribute fattr; + file_iterator end; + for(file_iterator i(path); i != end; ++i) + { + if((i->name.size() == 0) || (i->name[0] == STR('.'))) + continue; + item_fs m; + m.name = i->name; + if(file_attrib(path + m.name, fattr)) + { + m.bytes = fattr.bytes; + m.directory = fattr.is_directory; + m.modified_time = fattr.modified; + } + else + { + m.bytes = 0; + m.directory = i->directory; + modified_file_time(path + i->name, m.modified_time); + } + + file_container_.push_back(m); + + if(m.directory) + path_.childset(m.name, 0); + } + std::sort(file_container_.begin(), file_container_.end(), pred_sort_fs()); + } + + void _m_load_cat_path(nana::string path) + { + if((path.size() == 0) || (path[path.size() - 1] != STR('/'))) + path += STR('/'); + + auto beg_node = tree_.selected(); + while(!beg_node.empty() && (beg_node != nodes_.home) && (beg_node != nodes_.filesystem)) + beg_node = beg_node.owner(); + + auto head = nana::filesystem::path_user(); + if(path.size() >= head.size() && (path.substr(0, head.size()) == head)) + {//This is HOME + path_.caption(STR("HOME")); + if(beg_node != nodes_.home) + nodes_.home->select(true); + } + else + { //Redirect to '/' + path_.caption(STR("FILESYSTEM")); + if(beg_node != nodes_.filesystem) + nodes_.filesystem->select(true); + head.clear(); + } + + if(head.size() == 0 || head[head.size() - 1] != STR('/')) + head += STR('/'); + + nana::filesystem::file_iterator end; + for(nana::filesystem::file_iterator i(head); i != end; ++i) + { + if(i->directory) + path_.childset(i->name, 0); + } + auto cat_path = path_.caption(); + if(cat_path.size() && cat_path[cat_path.size() - 1] != STR('/')) + cat_path += STR('/'); + + auto beg = head.size(); + while(true) + { + auto pos = path.find(STR('/'), beg); + auto folder = path.substr(beg, pos != path.npos ? pos - beg: path.npos); + if(folder.size() == 0) break; + (cat_path += folder) += STR('/'); + (head += folder) += STR('/'); + path_.caption(cat_path); + + for(nana::filesystem::file_iterator i(head); i != end; ++i) + { + if(i->directory) + path_.childset(i->name, 0); + } + + if(pos == path.npos) + break; + beg = pos + 1; + } + _m_load_path(path); + _m_list_fs(); + } + + bool _m_filter_allowed(const nana::string& name, bool is_dir, const nana::string& filter, const std::vector* extension) const + { + if(filter.size() && (name.find(filter) == filter.npos)) + return false; + + if((is_dir || 0 == extension) || (0 == extension->size())) return true; + + for(auto & extstr : *extension) + { + auto pos = name.rfind(extstr); + if((pos != name.npos) && (name.size() == pos + extstr.size())) + return true; + } + return false; + } + + void _m_list_fs() + { + nana::string filter = filter_.caption(); + ls_file_.auto_draw(false); + + ls_file_.clear(); + + std::vector* ext_types = cb_types_.anyobj >(cb_types_.option()); + auto cat = ls_file_.at(0); + for(auto & fs: file_container_) + { + if(_m_filter_allowed(fs.name, fs.directory, filter, ext_types)) + { + cat.append(fs).value(fs); + } + } + ls_file_.auto_draw(true); + } + + void _m_finish(kind::t type, const nana::string& tar) + { + selection_.target = tar; + selection_.type = type; + close(); + } + + struct folder_creator + { + folder_creator(filebox_implement& fb, form & fm, textbox& tx) + : fb_(fb), fm_(fm), tx_path_(tx) + {} + + void operator()() + { + auto path = tx_path_.caption(); + + msgbox mb(fm_, STR("Create Folder")); + mb.icon(msgbox::icon_warning); + if(0 == path.size() || path[0] == STR('.') || path[0] == STR('/')) + { + mb< * exts = cb_types_.anyobj >(cb_types_.option()); + if(0 == exts || exts->size() == 0) return false; + + auto & ext = exts->at(0); + if(def_ext_[0] != STR('.')) + tar += STR('.'); + tar += ext; + return true; + } + private: + void _m_sel_file(const arg_mouse& arg) + { + auto sel = ls_file_.selected(); + if(sel.empty()) + return; + + auto index = sel[0]; + item_fs m; + ls_file_.at(index).resolve_to(m); + + if(event_code::dbl_click == arg.evt_code) + { + if(m.directory) + _m_load_cat_path(addr_.filesystem + m.name + STR("/")); + else + _m_finish(kind::filesystem, addr_.filesystem + m.name); + } + else + { + if(false == m.directory) + { + selection_.target = addr_.filesystem + m.name; + tb_file_.caption(m.name); + } + } + } + + void _m_ok() + { + if(0 == selection_.target.size()) + { + auto file = tb_file_.caption(); + if(file.size()) + { + if(file[0] == STR('.')) + { + msgbox mb(*this, caption()); + mb.icon(msgbox::icon_warning); + mb<()) + { + nana::string path = tree_.make_key_path(node, STR("/")) + STR("/"); + _m_resolute_path(path); + + nana::filesystem::file_iterator end; + for(nana::filesystem::file_iterator i(path); i != end; ++i) + { + if((false == i->directory) || (i->name.size() && i->name[0] == '.')) continue; + auto child = node.append(i->name, i->name, kind::filesystem); + if(!child.empty()) + { + for(nana::filesystem::file_iterator u(path + i->name); u != end; ++u) + { + if(false == u->directory || (u->name.size() && u->name[0] == '.')) continue; + + child.append(u->name, u->name, kind::filesystem); + break; + } + } + } + } + } + private: + bool io_read_; + nana::string def_ext_; + + place place_; + categorize path_; + textbox filter_; + button btn_folder_; + treebox tree_; + listbox ls_file_; + + label lb_file_; + textbox tb_file_; + combox cb_types_; + button btn_ok_, btn_cancel_; + + struct tree_node_tag + { + item_proxy home; + item_proxy filesystem; + }nodes_; + + std::vector file_container_; + struct path_tag + { + nana::string filesystem; + }addr_; + + struct selection_tag + { + kind::t type; + nana::string target; + }selection_; + + static nana::string saved_init_path; + static nana::string saved_selected_path; + };//end class filebox_implement + nana::string filebox_implement::saved_init_path; + nana::string filebox_implement::saved_selected_path; + +#endif + //class filebox + struct filebox::implement + { + struct filter + { + nana::string des; + nana::string type; + }; + + window owner; + bool open_or_save; + + nana::string file; + nana::string title; + nana::string path; + std::vector filters; + }; + + filebox::filebox(window owner, bool open) + : impl_(new implement) + { + impl_->owner = owner; + impl_->open_or_save = open; +#if defined(NANA_WINDOWS) + auto len = ::GetCurrentDirectory(0, nullptr); + if(len) + { + impl_->path.resize(len + 1); + ::GetCurrentDirectory(len, &(impl_->path[0])); + impl_->path.resize(len); + } +#endif + } + + filebox::~filebox() + { + delete impl_; + } + + nana::string filebox::title(nana::string s) + { + impl_->title.swap(s); + return s; + } + + filebox& filebox::init_path(const nana::string& ipstr) + { + if(ipstr.empty()) + { + impl_->path.clear(); + } + else + { + nana::filesystem::attribute attr; + if (nana::filesystem::file_attrib(ipstr, attr)) + if (attr.is_directory) + impl_->path = ipstr; + } + return *this; + } + + filebox& filebox::init_file(const nana::string& ifstr) + { + impl_->file = ifstr; + return *this; + } + + filebox& filebox::add_filter(const nana::string& description, const nana::string& filetype) + { + implement::filter flt = {description, filetype}; + impl_->filters.push_back(flt); + return *this; + } + + nana::string filebox::path() const + { + return impl_->path; + } + + nana::string filebox::file() const + { + return impl_->file; + } + + bool filebox::show() const + { +#if defined(NANA_WINDOWS) + if(impl_->file.size() < 520) + impl_->file.resize(520); + + OPENFILENAME ofn; + memset(&ofn, 0, sizeof ofn); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = reinterpret_cast(API::root(impl_->owner)); + ofn.lpstrFile = &(impl_->file[0]); + ofn.nMaxFile = static_cast(impl_->file.size() - 1); + + const nana::char_t * filter; + nana::string filter_holder; + if(impl_->filters.size()) + { + for(auto & f : impl_->filters) + { + filter_holder += f.des; + filter_holder += static_cast('\0'); + nana::string fs = f.type; + std::size_t pos = 0; + while(true) + { + pos = fs.find(STR(" "), pos); + if(pos == fs.npos) + break; + fs.erase(pos); + } + filter_holder += fs; + filter_holder += static_cast('\0'); + } + filter = filter_holder.data(); + } + else + filter = STR("All Files\0*.*\0"); + + ofn.lpstrFilter = filter; + ofn.lpstrTitle = (impl_->title.size() ? impl_->title.c_str() : nullptr); + ofn.nFilterIndex = 0; + ofn.lpstrFileTitle = nullptr; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = (impl_->path.size() ? impl_->path.c_str() : nullptr); + if(FALSE == (impl_->open_or_save ? ::GetOpenFileName(&ofn) : ::GetSaveFileName(&ofn))) + return false; + + impl_->file.resize(nana::strlen(impl_->file.data())); +#elif defined(NANA_LINUX) + filebox_implement fb(impl_->owner, impl_->open_or_save, impl_->title); + + if(impl_->filters.size()) + { + for(auto & f: impl_->filters) + { + nana::string fs = f.type; + std::size_t pos = 0; + while(true) + { + pos = fs.find(STR(" "), pos); + if(pos == fs.npos) + break; + fs.erase(pos); + } + fb.add_filter(f.des, fs); + } + } + else + fb.add_filter(STR("All Files"), STR("*.*")); + + fb.load_fs(impl_->path, impl_->file); + + API::modal_window(fb); + if(false == fb.file(impl_->file)) + return false; +#endif + auto tpos = impl_->file.find_last_of(STR("\\/")); + if(tpos != impl_->file.npos) + impl_->path = impl_->file.substr(0, tpos); + else + impl_->path.clear(); + + return true; + }//end class filebox +}//end namespace nana diff --git a/source/gui/layout_utility.cpp b/source/gui/layout_utility.cpp new file mode 100644 index 00000000..a190b714 --- /dev/null +++ b/source/gui/layout_utility.cpp @@ -0,0 +1,264 @@ +/* + * Utility Implementation + * Copyright(C) 2003-2013 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/gui/layout_utility.hpp + * + * + */ +#include + +namespace nana +{ + //overlap test if overlaped between r1 and r2 + bool overlap(const rectangle& r1, const rectangle& r2) + { + if(r1.y + int(r1.height) <= r2.y) return false; + if(r1.y >= int(r2.y + r2.height)) return false; + + if(int(r1.x + r1.width) <= r2.x) return false; + if(r1.x >= int(r2.x + r2.width)) return false; + + return true; + } + + //overlap, compute the overlap area between r1 and r2. the rect is for root + bool overlap(const rectangle& r1, const rectangle& r2, rectangle& r) + { + if(overlap(r1, r2)) + { + auto l1 = static_cast(r1.x) + r1.width; + auto l2 = static_cast(r2.x) + r2.width; + + auto b1 = static_cast(r1.y) + r1.height; + auto b2 = static_cast(r2.y) + r2.height; + + r.x = r1.x < r2.x ? r2.x : r1.x; + r.y = r1.y < r2.y ? r2.y : r1.y; + + r.width = static_cast(l1 < l2 ? l1 - r.x: l2 - r.x); + r.height = static_cast(b1 < b2 ? b1 - r.y: b2 - r.y); + + return true; + } + return false; + } + + + bool overlap(const rectangle& ir, const size& valid_input_area, const rectangle & dr, const size& valid_dst_area, rectangle& op_ir, rectangle& op_dr) + { + if(overlap(ir, valid_input_area, op_ir) == false) + return false; + + rectangle good_dr; + if(overlap(dr, valid_dst_area, good_dr) == false) + return false; + + zoom(ir, op_ir, dr, op_dr); + + if(false == covered(op_dr, good_dr)) + { + op_dr = good_dr; + zoom(dr, good_dr, ir, op_ir); + } + return true; + } + + bool intersection(const rectangle & r, point pos_beg, point pos_end, point& good_pos_beg, point& good_pos_end) + { + const int right = r.right(); + const int bottom = r.bottom(); + + if(pos_beg.x > pos_end.x) + std::swap(pos_beg, pos_end); + + bool good_beg = (0 <= pos_beg.x && pos_beg.x < right && 0 <= pos_beg.y && pos_beg.y < bottom); + bool good_end = (0 <= pos_end.x && pos_end.x < right && 0 <= pos_end.y && pos_end.y < bottom); + + + if(good_beg && good_end) + { + good_pos_beg = pos_beg; + good_pos_end = pos_end; + return true; + } + else if(pos_beg.x == pos_end.x) + { + if(r.x <= pos_beg.x && pos_beg.x < right) + { + if(pos_beg.y < r.y) + { + if(pos_end.y < r.y) + return false; + good_pos_beg.y = r.y; + good_pos_end.y = (pos_end.y < bottom ? pos_end.y : bottom - 1); + } + else if(pos_beg.y >= bottom) + { + if(pos_end.y >= bottom) + return false; + good_pos_beg.y = bottom - 1; + good_pos_end.y = (pos_end.y < r.y ? r.y : pos_end.y); + } + + good_pos_beg.x = good_pos_end.x = r.x; + return true; + } + return false; + } + else if(pos_beg.y == pos_end.y) + { + if(r.y <= pos_beg.y && pos_beg.y < bottom) + { + if(pos_beg.x < r.x) + { + if(pos_end.x < r.x) + return false; + good_pos_beg.x = r.x; + good_pos_end.x = (pos_end.x < right ? pos_end.x : right - 1); + } + else if(pos_beg.x >= right) + { + if(pos_end.x >= right) + return false; + + good_pos_beg.x = right - 1; + good_pos_end.x = (pos_end.x < r.x ? r.x : pos_end.x); + } + good_pos_beg.y = good_pos_end.y = r.y; + return true; + } + return false; + } + + double m = (pos_end.y - pos_beg.y ) / double(pos_end.x - pos_beg.x); + bool is_nw_to_se = (m >= 0.0); + //The formulas for the line. + //y = m * (x - pos_beg.x) + pos_beg.y + //x = (y - pos_beg.y) / m + pos_beg.x + if(!good_beg) + { + good_pos_beg.y = static_cast(m * (r.x - pos_beg.x)) + pos_beg.y; + if(r.y <= good_pos_beg.y && good_pos_beg.y < bottom) + { + good_pos_beg.x = r.x; + } + else + { + bool cond; + int y; + if(is_nw_to_se) + { + y = r.y; + cond = good_pos_beg.y < y; + } + else + { + y = bottom - 1; + cond = good_pos_beg.y > y; + } + + if(cond) + { + good_pos_beg.x = static_cast((y - pos_beg.y) / m) + pos_beg.x; + if(r.x <= good_pos_beg.x && good_pos_beg.x < right) + good_pos_beg.y = y; + else + return false; + } + else + return false; + } + + if(good_pos_beg.x < pos_beg.x) + return false; + } + else + good_pos_beg = pos_beg; + + if(!good_end) + { + good_pos_end.y = static_cast(m * (right - 1 - pos_beg.x)) + pos_beg.y; + if(r.y <= good_pos_end.y && good_pos_end.y < bottom) + { + good_pos_end.x = right - 1; + } + else + { + bool cond; + int y; + if(is_nw_to_se) + { + y = bottom - 1; + cond = good_pos_end.y > y; + } + else + { + y = r.y; + cond = good_pos_end.y < y; + } + + if(cond) + { + good_pos_end.x = static_cast((y - pos_beg.y) / m) + pos_beg.x; + if(r.x <= good_pos_end.x && good_pos_end.x < right) + good_pos_end.y = y; + else + return false; + } + else + return false; + } + if(good_pos_end.x > pos_end.x) + return false; + } + else + good_pos_end = pos_end; + + return true; + } + + void fit_zoom(const size& input_s, const size& ref_s, size& result_s) + { + double rate_input = double(input_s.width) / double(input_s.height); + double rate_ref = double(ref_s.width) / double(ref_s.height); + + if(rate_input < rate_ref) + { + result_s.height = ref_s.height; + result_s.width = static_cast(ref_s.height * rate_input); + } + else if(rate_input > rate_ref) + { + result_s.width = ref_s.width; + result_s.height = static_cast(ref_s.width / rate_input); + } + else + result_s = ref_s; + } + + void zoom(const rectangle& ref, const rectangle& scaled, const rectangle& ref_dst, rectangle& r) + { + double rate_x = (scaled.x - ref.x) / double(ref.width); + double rate_y = (scaled.y - ref.y) / double(ref.height); + + r.x = static_cast(rate_x * ref_dst.width) + ref_dst.x; + r.y = static_cast(rate_y * ref_dst.height) + ref_dst.y; + + r.width = static_cast(scaled.width / double(ref.width) * ref_dst.width); + r.height = static_cast(scaled.height / double(ref.height) * ref_dst.height); + } + + //covered test if r2 covers r1. + bool covered(const rectangle& r1, //Rectangle 1 is must under rectangle 2 + const rectangle& r2) //Rectangle 2 + { + if(r1.x < r2.x || r1.right() > r2.right()) return false; + if(r1.y < r2.y || r1.bottom() > r2.bottom()) return false; + return true; + } +} diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp new file mode 100644 index 00000000..1b37d4be --- /dev/null +++ b/source/gui/msgbox.cpp @@ -0,0 +1,464 @@ +/* + * A Message Box Class + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/msgbox.hpp + */ +#include +#include +#if defined(NANA_WINDOWS) + #include +#elif defined(NANA_X11) + #include + #include + #include + #include + #include + #include +#endif + +namespace nana +{ +#if defined(NANA_X11) + class msgbox_window + : public form + { + public: + msgbox_window(window wd, const nana::string& title, msgbox::button_t btn, msgbox::icon_t ico) + : form(wd, nana::rectangle(1, 1, 1, 1), appear::decorate<>()), + owner_(wd), pick_(msgbox::pick_yes) + { + this->caption(title); + drawing dw(*this); + dw.draw([this](::nana::paint::graphics& graph) + { + graph.rectangle(nana::rectangle{0, 0, graph.width(), graph.height() - 50}, 0xFFFFFF, true); + if(ico_.empty() == false) + ico_.stretch(ico_.size(), graph, ::nana::rectangle{12, 25, 32, 32}); + }); + + unsigned width_pixel = 45; + unsigned height_pixel = 110; + + place_.bind(*this); + + yes_.create(*this); + yes_.events().click([this](const arg_mouse& arg) + { + _m_click(arg); + }); + yes_.caption(STR("OK")); + width_pixel += 77; + + if(msgbox::yes_no == btn || msgbox::yes_no_cancel == btn) + { + yes_.caption(STR("Yes")); + no_.create(*this); + no_.caption(STR("No")); + no_.events().click([this](const arg_mouse& arg) + { + _m_click(arg); + }); + + width_pixel += 77; + + if(msgbox::yes_no_cancel == btn) + { + cancel_.create(*this); + cancel_.caption(STR("Cancel")); + cancel_.events().click([this](const arg_mouse& arg) + { + _m_click(arg); + }); + + width_pixel += 77; + pick_ = msgbox::pick_cancel; + } + else + pick_ = msgbox::pick_no; + } + + std::stringstream ss; + ss<<"vert<>>"; + place_.div(ss.str().data()); + + auto & field = place_.field("buttons"); + field<size(nana::size{width_pixel, height_pixel}); + _m_icon(ico); + } + + void prompt(const nana::string& text) + { + if(text.size()) + { + const unsigned ico_pixels = (ico_.empty() ? 0 : 44); + const unsigned text_pixels = 500 - ico_pixels; + text_.create(*this, nana::rectangle(12 + ico_pixels, 25, 1, 1)); + + text_.background(0xFFFFFF); + text_.caption(text); + + nana::size ts = text_.measure(text_pixels); + + if(ts.height <= 32) + text_.move(12 + ico_pixels, 25 + (32 - ts.height) / 2); + + text_.size(ts); + + nana::size sz = this->size(); + if(sz.width < 48 + ts.width + ico_pixels) + sz.width = 48 + ts.width + ico_pixels; + + nana::rectangle r = API::make_center(owner_, sz.width, sz.height + ts.height); + this->move(r); + } + + API::modal_window(*this); + } + + msgbox::pick_t pick() const + { + return pick_; + } + private: + void _m_icon(msgbox::icon_t ico) + { + if(ico == msgbox::icon_none) return; + const unsigned pic_information[] = { + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBFBFBF, 0xEBEBEB, 0xDADADB, 0xBDBFC4, 0xA9AFBE, 0x99A3BF, 0x8D9ABF, 0x8895B8, 0x8691AC, 0x8F95A6, 0xA8AAB0, 0xD5D6D7, 0xEBEBEB, 0xBFBFBF, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEDEDED, 0xC7C8CA, 0xB8BFD2, 0x9CB1E6, 0x7C99E2, 0x7191E1, 0x6C8DE0, 0x6789DE, 0x6487DC, 0x6285D7, 0x6381D0, 0x617EC8, 0x687EB7, 0x7F889F, 0xB9BABE, 0xEDEDED, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xDDDEDE, 0xBABFCC, 0x9AB2EE, 0x7494E5, 0x698DE7, 0x668CE8, 0x628AE9, 0x5D85E7, 0x527CE4, 0x4D79E1, 0x527BDF, 0x577DDD, 0x567BD7, 0x577ACF, 0x5878C6, 0x5E77B5, 0x80889B, 0xDADADB, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xCACBCB, 0xAFBBD8, 0x7C99E6, 0x688BE5, 0x638AEA, 0x6187E9, 0x5C85E9, 0x5B83E7, 0x5781E7, 0x91ADF2, 0xA5BDF5, 0x688CE6, 0x4A74DA, 0x4F78DA, 0x4D76D6, 0x4D73D1, 0x4F72C7, 0x5472B9, 0x66759A, 0xC1C2C4, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xCACBCB, 0xA2B2D9, 0x6E8FE0, 0x6287E3, 0x5D85E8, 0x5B84E7, 0x5A83E8, 0x5982E6, 0x527CE3, 0xB8CBF9, 0xFFFFFF, 0xFFFFFF, 0xF4FAFF, 0x6587DF, 0x466FD6, 0x4972D5, 0x4770D1, 0x456DCE, 0x476CC7, 0x4E6DB8, 0x5E709A, 0xC1C2C4, 0xD3D3D3, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xDDDEDE, 0x9FABCB, 0x6D8DDF, 0x5E84E1, 0x5982E5, 0x5981E3, 0x5780E3, 0x5780E3, 0x527CE1, 0x5C83E3, 0xFCFEFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xA7BAE8, 0x3965D0, 0x4770D2, 0x436CD0, 0x4269CC, 0x4068C9, 0x4267C2, 0x4968B4, 0x5E6C91, 0xD9D9DA, 0xB9B8B8, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEDEDED, 0x9CA2AE, 0x7493E0, 0x5A80DD, 0x557EE0, 0x547DE1, 0x537DE1, 0x547CE0, 0x537CE0, 0x507ADF, 0x4F78DC, 0xDBE4FB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0x7B92CF, 0x3C65D0, 0x456CD0, 0x4169CE, 0x3F67CB, 0x3D64C8, 0x3D63C6, 0x3E62BE, 0x4663AC, 0x757D90, 0xEDEDED, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF, + 0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xBFC0C1, 0x7D95D2, 0x5B7FD8, 0x527ADC, 0x5279DD, 0x5179DC, 0x5079DC, 0x5079DC, 0x5078DC, 0x4F78DB, 0x4771D9, 0x6485DA, 0xCDD5EA, 0xE0E4ED, 0x92A2CB, 0x3C61C1, 0x436AD2, 0x4168CE, 0x3F65CB, 0x3C63C9, 0x3962C7, 0x3960C4, 0x385DC0, 0x3C5EB7, 0x475F9F, 0xB4B6B9, 0xBFBFBF, 0xAAA9A9, 0xFFFFFF, + 0xE9E9E9, 0x807F7F, 0xEBEBEB, 0x8C93A5, 0x6284D5, 0x5177D6, 0x4E75D9, 0x4D76DA, 0x4D75D9, 0x4D75D9, 0x4D75D9, 0x4B74D8, 0x4A73D8, 0x4B73D8, 0x3F68D3, 0x3860C9, 0x395EBF, 0x325AC5, 0x4068D2, 0x436AD0, 0x4067CE, 0x3E64CB, 0x3C62C8, 0x395FC6, 0x375EC4, 0x365BC0, 0x365BBB, 0x3E5DAC, 0x667089, 0xEBEBEB, 0x807F7F, 0xE9E9E9, + 0xC7C6C6, 0xA2A2A2, 0xD6D6D7, 0x7387BC, 0x5276CF, 0x4A73D5, 0x4972D6, 0x4972D7, 0x4972D7, 0x4972D6, 0x4871D6, 0x4870D5, 0x486FD5, 0x456BD3, 0x4B6FD5, 0x4D72D6, 0x4C71D6, 0x4E72D5, 0x4267CD, 0x3057BF, 0x2E54BC, 0x2950B8, 0x274EB5, 0x264BB4, 0x264DB3, 0x274DB5, 0x2A4FB4, 0x3254AD, 0x435995, 0xD2D2D3, 0xA3A3A3, 0xC7C6C6, + 0xA9A8A8, 0xC0C0C0, 0xA6A8AD, 0x5C7AC3, 0x4B72CD, 0x476FD2, 0x466FD2, 0x466FD3, 0x466DD3, 0x466DD3, 0x466DD2, 0x456CD2, 0x436BD3, 0x436BD2, 0xA3B3DD, 0xF5F5F0, 0xEBEAE7, 0xC3CCE6, 0x2C4383, 0xB32A2, 0x1A41A9, 0x1A40A8, 0x1A40A9, 0x1B41A9, 0x1A41A8, 0x1B40A8, 0x1C41A9, 0x2245A5, 0x314D99, 0x9598A0, 0xC1C1C1, 0xA9A8A8, + 0x8F8E8E, 0xDADADA, 0x878D9A, 0x5172C3, 0x456CCD, 0x436BCF, 0x426BD0, 0x416BD0, 0x426AD0, 0x426AD0, 0x426AD0, 0x426AD1, 0x3A61CB, 0x3056BE, 0xCFCECE, 0xD0CDCA, 0xC1C1C1, 0xE5E4E3, 0x334984, 0xB31A3, 0x1C42AD, 0x1C41AB, 0x1C41AB, 0x1B41AC, 0x1B41AB, 0x1C41AB, 0x1C41AB, 0x1F43A8, 0x2B499C, 0x6A7184, 0xDADADA, 0x8F8E8E, + 0x7C7B7B, 0xEDEDED, 0x737C95, 0x4C6FC3, 0x4169CB, 0x3F68CD, 0x3F67CD, 0x3F67CD, 0x3F67CD, 0x4068CF, 0x3E64CD, 0x2F56BE, 0x1C42AD, 0x2046AF, 0xCACCCC, 0xC5C4C0, 0xB9B9B9, 0xE3E2E1, 0x324784, 0xB31A4, 0x1C42AD, 0x1B40AC, 0x1B40AC, 0x1B40AC, 0x1B40AC, 0x1B40AB, 0x1B40AB, 0x1E41A9, 0x29479F, 0x4C5979, 0xEDEDED, 0x7C7B7B, + 0x6F6E6E, 0xFBFBFB, 0x697597, 0x476AC1, 0x3E65C7, 0x3C64C9, 0x3C63CA, 0x3D63CA, 0x3D64CB, 0x355CC5, 0x2349B3, 0x1B41AB, 0x1A40AB, 0x2449B1, 0xCACAC9, 0xBCB9B7, 0xB1B1B1, 0xE1E0DE, 0x324784, 0xB30A5, 0x1B41AE, 0x1B3FAD, 0x1B3FAD, 0x1B3FAD, 0x1B3FAD, 0x1B3FAC, 0x1B3FAC, 0x1D41AA, 0x2645A1, 0x414F7B, 0xFBFBFB, 0x6F6E6E, + 0x6F6E6E, 0xFBFBFB, 0x667395, 0x4467BF, 0x3A62C5, 0x3960C7, 0x3961C7, 0x3A61C8, 0x2E56BE, 0x1E45AE, 0x1C42AC, 0x1E43AE, 0x1B41AD, 0x2448B3, 0xC8C8C9, 0xB5B3AF, 0xADADAC, 0xE0DFDE, 0x324784, 0xB31A6, 0x1B40AF, 0x1B3FAE, 0x1B3FAE, 0x1B3FAE, 0x1B3FAE, 0x1B3FAE, 0x1B3FAD, 0x1D40AB, 0x2646A2, 0x404F7B, 0xFBFBFB, 0x6F6E6E, + 0x7C7B7B, 0xEDEDED, 0x6B758E, 0x4264B9, 0x385FC2, 0x365EC5, 0x375FC6, 0x2C52BC, 0x1E45AE, 0x1E43AE, 0x1E43AE, 0x1D43AE, 0x1A3FAE, 0x2549B5, 0xC6C7C9, 0xAFAEA9, 0xABABAB, 0xE1E0DE, 0x324784, 0xC30A7, 0x1C40B1, 0x1C3FB1, 0x1C3FB0, 0x1C3FB0, 0x1C3FB0, 0x1B3FAF, 0x1B3FAE, 0x1E41AC, 0x2946A1, 0x4A5678, 0xEDEDED, 0x7C7B7B, + 0x8F8E8E, 0xDADADA, 0x7D838F, 0x3E60B3, 0x375DBE, 0x365BC1, 0x2B52BA, 0x1E45AE, 0x1E45AF, 0x1E43AF, 0x1E43AF, 0x1D42AF, 0x1A3FAE, 0x2549B5, 0xC6C7C7, 0xAFAEA9, 0xAEAEAE, 0xE1E1DE, 0x324785, 0xC30A9, 0x1C40B5, 0x1C3FB4, 0x1D3FB4, 0x1D3FB4, 0x1C3FB3, 0x1C3FB3, 0x1D3FB0, 0x2041AD, 0x2C48A0, 0x656C80, 0xDADADA, 0x8F8E8E, + 0xA9A8A8, 0xC0C0C0, 0x9EA0A6, 0x425EAA, 0x365BBA, 0x2D53B9, 0x1F46AF, 0x1F46AF, 0x1E43AF, 0x1E43AF, 0x1E42AF, 0x1D42B0, 0x1A3FAF, 0x2449B6, 0xC6C7C9, 0xB4B3AF, 0xB5B5B6, 0xE4E4E1, 0x334786, 0xD30AD, 0x1D41B8, 0x1E3FB7, 0x1D40B7, 0x1D3FB7, 0x1D3FB7, 0x1D3FB6, 0x1E3FB3, 0x2243AE, 0x294398, 0x94979F, 0xC1C1C1, 0xA9A8A8, + 0xC7C6C6, 0xA2A2A2, 0xD3D3D4, 0x4D629B, 0x3558B3, 0x224AB0, 0x1F46B0, 0x1F45B0, 0x1E45B0, 0x1E43B0, 0x1D42B0, 0x1D42B1, 0x1A3FB1, 0x2447B7, 0xC8C8C9, 0xBDBCB7, 0xBFBFC0, 0xE8E6E5, 0x334786, 0xD30AF, 0x1E41BC, 0x1F40BA, 0x1E40BA, 0x1E40BA, 0x1E40B9, 0x1E40B8, 0x1F40B6, 0x2845AD, 0x32468B, 0xD2D2D3, 0xA3A3A3, 0xC7C6C6, + 0xE9E9E9, 0x807F7F, 0xEBEBEB, 0x6D7489, 0x3251A6, 0x2448AC, 0x2046AF, 0x1F45B0, 0x1E43B0, 0x1E42B1, 0x1E42B1, 0x1D42B1, 0x1B3FB3, 0x2447B9, 0xD0D0CF, 0xC7C6C2, 0xCACBCB, 0xEBEBE9, 0x344887, 0xE30B1, 0x1F41BF, 0x1F40BE, 0x1F40BE, 0x1F40BD, 0x1F40BD, 0x1F40BB, 0x2443B6, 0x2E49A8, 0x5B6380, 0xEBEBEB, 0x818080, 0xE9E9E9, + 0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xB5B6B8, 0x375092, 0x294BA7, 0x2146AE, 0x2045B0, 0x1E43B1, 0x1E42B1, 0x1E42B1, 0x1D41B3, 0x1B3FB4, 0x2347B9, 0xD5D7D8, 0xD6D5D0, 0xDFDEDF, 0xF2F1EF, 0x344988, 0xE2FB4, 0x2142C1, 0x2041C1, 0x2041C0, 0x2041C0, 0x2140BF, 0x2241BD, 0x2A47B4, 0x304493, 0xB4B5B9, 0xC0C0C0, 0xAAA9A9, 0xFFFFFF, + 0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEDEDED, 0x6E7484, 0x2F4B9E, 0x2648AB, 0x2046B0, 0x1E42B1, 0x1E42B3, 0x1E42B4, 0x1E41B5, 0x1B3FB6, 0x2346B9, 0xDFDFE3, 0xEBE9E7, 0xF3F3F4, 0xF3F3F2, 0x364988, 0xE2FB5, 0x2342C4, 0x2141C4, 0x2141C4, 0x2141C2, 0x2342C0, 0x2745BA, 0x344CAA, 0x697088, 0xEDEDED, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xD8D8D9, 0x4C597E, 0x2E4BA1, 0x2548AD, 0x1F43B2, 0x1F42B3, 0x1E42B5, 0x1E41B7, 0x1C3FB8, 0x2143B9, 0xEBEBED, 0xFDFDFA, 0xFCFCFD, 0xF3F3F2, 0x374B8A, 0xE30B7, 0x2443C6, 0x2342C6, 0x2442C5, 0x2542C3, 0x2845BE, 0x334BB0, 0x475484, 0xDBDBDB, 0xBAB9B9, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xBEBEC0, 0x445584, 0x2D4AA2, 0x2546AE, 0x2043B3, 0x2042B5, 0x1F42B8, 0x1D3FBA, 0x1F40B9, 0xB9C0D3, 0xF5F5F6, 0xF5F5F5, 0xC7CCDD, 0x304386, 0x1231B9, 0x2443C8, 0x2442C6, 0x2543C5, 0x2A46BF, 0x344CB3, 0x414F89, 0xC1C2C5, 0xD4D4D4, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xBFBFC1, 0x4B587F, 0x2E49A0, 0x2848AB, 0x2344B3, 0x2143B7, 0x2142BC, 0x1F40BE, 0x354689, 0x475282, 0x455184, 0x424E83, 0x2942B3, 0x2240C7, 0x2644C7, 0x2945C3, 0x2E48BC, 0x354CB0, 0x4A5587, 0xC3C3C6, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xD8D8D9, 0x6C7183, 0x324993, 0x2B47A7, 0x2947B2, 0x2645B8, 0x2444BD, 0x1B3BBC, 0x1635B5, 0x1735B5, 0x1837B8, 0x2442C3, 0x2B48C3, 0x2D48BD, 0x324AB4, 0x33479C, 0x6D728B, 0xDBDCDC, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEDEDED, 0xB1B2B5, 0x5E6680, 0x374B92, 0x2E46A3, 0x2D47AE, 0x2C47B4, 0x2C47B9, 0x2D47BB, 0x2E48B8, 0x3049B5, 0x2E46AB, 0x364996, 0x5F6685, 0xB6B8BC, 0xEDEDED, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBFBFBF, 0xEBEBEB, 0xD1D1D2, 0x93969F, 0x666C82, 0x4E587F, 0x434F83, 0x434F83, 0x4E5880, 0x686E86, 0x9698A1, 0xD3D4D5, 0xEBEBEB, 0xBFBFBF, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + }; + const unsigned pic_warning[] = { + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFDFDFD, 0xD6D7D7, 0xD8D7D8, 0xECECEC, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE6E6E5, 0xB5B5B9, 0xBBBAC3, 0xC8C8C9, 0xFEFEFE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF3F3F3, 0xAFB0B3, 0xBFBFB7, 0xC2C2AC, 0xB2B2B8, 0xDADADA, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xC9C9C8, 0xADAEBF, 0xB8B26D, 0xC7B81E, 0xBBBBB8, 0xB3B4BB, 0xF7F7F8, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E8, 0xAEAEB5, 0xAEAEAC, 0xD6C611, 0xE4DB06, 0xBCAC4D, 0xB5B8CB, 0xCBCBCB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFDFDFD, 0xC0C0C0, 0xB4B4C2, 0xB6AA53, 0xFFFF00, 0xFFFF00, 0xD1C00E, 0xBDB8A0, 0xB3B4BE, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xDBDBDB, 0xB2B2BD, 0xB6B6A6, 0xDDCC07, 0xFFFF00, 0xFFFF00, 0xFFFD00, 0xBBA63E, 0xC3C4D6, 0xC0C0C2, 0xFEFEFE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF8F8F7, 0xB2B2B5, 0xC3C3D4, 0xBCAC4A, 0xFFFF00, 0xFFF700, 0xFFF700, 0xFFFD00, 0xD2BC0B, 0xCAC39C, 0xB8B9C7, 0xE4E3E4, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xCFCFCF, 0xB9B9C7, 0xC1BF97, 0xDBC907, 0x989533, 0x747144, 0x757442, 0x7F7D45, 0xDCCE0D, 0xC4AC31, 0xC6C8D3, 0xBEBEC1, 0xFCFCFC, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEEEEEE, 0xB6B6BB, 0xCDCECE, 0xC6B63D, 0xFAF400, 0x6D6D65, 0x65657E, 0x646578, 0x5E5E74, 0xC4B71F, 0xE4CA0D, 0xC5B679, 0xC5C8D5, 0xD4D4D5, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFEFEFE, 0xC6C6C6, 0xD5D6E2, 0xC7C48C, 0xE0D306, 0xF9F303, 0x76755B, 0x676771, 0x65656A, 0x5D5E62, 0xC6B720, 0xFFEE08, 0xC0A32B, 0xE7E6E8, 0xBBBCC2, 0xF3F3F4, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE4E4E4, 0xBDBEC7, 0xC8C9C5, 0xD7C21D, 0xFFFD01, 0xFCF405, 0x747151, 0x5A5B66, 0x56575B, 0x4D4E4F, 0xC9B71D, 0xFFEA15, 0xE6C60A, 0xC2AB64, 0xE8EAF5, 0xC9C9C9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFCFCFC, 0xB7B7B9, 0xE8E9F2, 0xC3B766, 0xF3E406, 0xFFF512, 0xF8EC0A, 0x706E45, 0x4A4B56, 0x45464B, 0x404041, 0xC9B418, 0xFFE313, 0xF9D708, 0xC3A21B, 0xDAD2BE, 0xC5C8CE, 0xECECEC, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD5D5D5, 0xC2C3CE, 0xC9C9B1, 0xDDC617, 0xFFF00F, 0xFFF019, 0xF8EB0A, 0x6C673A, 0x373844, 0x37383C, 0x3E3D3A, 0xCBB415, 0xFFDD0D, 0xF7D30B, 0xE4B903, 0xBFA449, 0xEDEEF6, 0xC3C3C5, 0xFDFDFD, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF3F3F3, 0xB6B7BB, 0xE8E9EF, 0xBFAF4F, 0xFFF00D, 0xFFEA1A, 0xFFEC1B, 0xF8E80D, 0x655E2D, 0x292A38, 0x34353B, 0x46453D, 0xD2B711, 0xFFD906, 0xF5CC05, 0xF7CB00, 0xCEA306, 0xC8B68C, 0xCBCDD8, 0xDFDFDF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xC0C0C2, 0xD4D5E4, 0xC7C39D, 0xDFC414, 0xFFEB18, 0xFDE41B, 0xFFE418, 0xF5D711, 0x534A15, 0x80916, 0x1E1F24, 0x3D3B31, 0xCFAD05, 0xFBCB00, 0xF0C300, 0xF0C100, 0xF0B900, 0xB69123, 0xE8EAEE, 0xBDBEC1, 0xF9F9F9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xECECEC, 0xB6B7BD, 0xD8D8D7, 0xC3AD43, 0xFFE506, 0xF8DA0A, 0xF4D302, 0xF7D300, 0xEFC900, 0x453900, 0x0, 0x6070F, 0x3A3829, 0xCDA601, 0xF5BF00, 0xEDB800, 0xEDB400, 0xF0B400, 0xCE9706, 0xC2AB77, 0xCBD0DD, 0xD7D6D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFCFCFC, 0xB8B8BA, 0xD8D9E5, 0xBAAB65, 0xECC902, 0xF4CD00, 0xF0CA00, 0xEEC600, 0xF3C800, 0xF2C600, 0x4D3D00, 0x0, 0x171922, 0x534F3D, 0xD3A901, 0xF4BA00, 0xEDB200, 0xEDB100, 0xECB000, 0xEDAE00, 0xB88B16, 0xCBC5BB, 0xBABCC0, 0xF3F3F3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xDEDEDE, 0xB4B5BF, 0xB8B8AC, 0xD1AE0D, 0xF6CD00, 0xEFC900, 0xEFC600, 0xEEC400, 0xF2C500, 0xF6C900, 0x5D4A00, 0x4, 0x202435, 0x5A5544, 0xD4A801, 0xF4B800, 0xEDB000, 0xECAF00, 0xEBAC00, 0xECAC00, 0xD99903, 0xB5964E, 0xC6CBDA, 0xC7C7C7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF8F8F8, 0xB2B3B5, 0xC4C5D1, 0xB9A550, 0xEAC102, 0xEFC800, 0xEEC500, 0xEEC400, 0xEEC200, 0xEEC100, 0xF0C000, 0xD1A100, 0xB38800, 0xBB9100, 0xCA9B00, 0xE5AB00, 0xEDB100, 0xEBAE00, 0xEAAC00, 0xEAA900, 0xE8A700, 0xEDA800, 0xC28B06, 0xB9AB8D, 0xB7BBC3, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xC7C7C8, 0xB9BCCB, 0xB5B090, 0xD5AE06, 0xF0C800, 0xEEC300, 0xEEC200, 0xEEC100, 0xEDBD00, 0xEDBB00, 0xF2BB00, 0xCD9E00, 0x907000, 0x806506, 0xB68A00, 0xF4B400, 0xEBAB00, 0xEAA900, 0xEAA800, 0xE7A600, 0xE7A400, 0xE7A300, 0xDC9803, 0xB18C36, 0xC2C5D3, 0xBFBFC0, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xF1F1F1, 0xAFB0B6, 0xB7B7B8, 0xBBA543, 0xEBBF02, 0xEEC400, 0xEEC100, 0xEEBF00, 0xEEBD00, 0xEDBA00, 0xEFBA00, 0xF4BD00, 0x765A00, 0x5, 0x161B33, 0x645A38, 0xDBA200, 0xEEAC00, 0xEAA800, 0xE8A700, 0xE7A400, 0xE7A400, 0xE7A400, 0xEBA600, 0xC58B06, 0xB19E75, 0xB6BBC5, 0xDEDEDE, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xBCBCBD, 0xB4B7C4, 0xB3AB77, 0xD8B006, 0xF3C805, 0xF0C506, 0xF0C305, 0xF0C102, 0xEFC001, 0xF0BC00, 0xF4BD00, 0xF5C000, 0x554200, 0xA, 0x343944, 0x5F5D57, 0xD19C06, 0xF3B300, 0xEBAE04, 0xEBAC05, 0xEAAB06, 0xEAAB06, 0xEBAB05, 0xECAC06, 0xE1A203, 0xB38823, 0xBCBBBF, 0xB5B7BB, 0xF8F8F8, 0xFFFFFF, + 0xFFFFFF, 0xE8E8E7, 0xAEAEB3, 0xB1AFA0, 0xC3AB45, 0xFED923, 0xF8D329, 0xF8D028, 0xF8CE27, 0xF8CD26, 0xF7CC24, 0xF8CB23, 0xF8CA22, 0xFFCE20, 0xC9A21E, 0x4C4324, 0x55544A, 0x9D863E, 0xECB821, 0xF7C228, 0xF3BD29, 0xF2BD2A, 0xF3BF2A, 0xF3BF29, 0xF3BF29, 0xF4BF29, 0xF9C227, 0xD19F19, 0xB09964, 0xB2B4BF, 0xD1D1D2, 0xFFFFFF, + 0xFFFFFF, 0xBABABB, 0xB7B8C0, 0xB6AA73, 0xCCA420, 0xCBA326, 0xCBA126, 0xCB9F26, 0xCB9E24, 0xCB9E24, 0xCB9E24, 0xCB9E23, 0xCA9E22, 0xCA9E22, 0xCE9E22, 0xC49822, 0xBB8F1F, 0xC59820, 0xC99B23, 0xC89B26, 0xC89A26, 0xC89A26, 0xC89B26, 0xC99B26, 0xC99B26, 0xC99B26, 0xCA9B26, 0xCC9E22, 0xBC9637, 0xBAB4B0, 0xB1B3B7, 0xEFEFF0, + 0xFFFFFF, 0xB2B3B4, 0xC9CACC, 0xD2CFC9, 0xD3CFCA, 0xD3CFCB, 0xD4CFCD, 0xD5D1CE, 0xD6D2CF, 0xDDDAD6, 0xE3DFDD, 0xEAE7E6, 0xEEEBEA, 0xEFEDEA, 0xEFEDEB, 0xF0EDEB, 0xF0EEEB, 0xEFEDEB, 0xEFEDEB, 0xEDEAE7, 0xE7E5E3, 0xE7E4E3, 0xDFDAD8, 0xD8D4D1, 0xD6D2CF, 0xD5D1CE, 0xD4CFCD, 0xD3CECB, 0xD4CFCD, 0xD0CECF, 0xBDBDC0, 0xC9C9C9, + 0xFFFFFF, 0xBBBBBB, 0x9F9FA0, 0x979799, 0x97979B, 0x97979B, 0x97989B, 0x98999C, 0x999B9C, 0x9B9C9E, 0x9C9CA1, 0x9C9DA1, 0x9DA1A2, 0xA1A1A3, 0xA1A1A3, 0xA1A2A4, 0xA2A2A4, 0xA1A2A4, 0xA1A1A3, 0xA1A1A3, 0x9EA1A2, 0x9D9EA1, 0x9D9DA0, 0x9C9D9E, 0x9A9B9D, 0x999A9D, 0x98999C, 0x97989B, 0x98989B, 0x989899, 0xA7A7A7, 0xE0E0E0, + 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xD1D1D1, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + }; + const unsigned pic_error[] = { + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEEEDED, 0xFBFBFB, 0xFBFBFB, 0xEEEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBFBFBF, 0xECEBEB, 0xEBD9D8, 0xE4BDBD, 0xDCA7A8, 0xD79596, 0xD48688, 0xCE7D7F, 0xD28B8C, 0xD9A2A1, 0xE1BEC0, 0xEAD9D9, 0xECEAEA, 0xBFBFBF, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEFECEC, 0xE5C2C3, 0xE1AEAD, 0xE89D9E, 0xE06F6F, 0xE15C5C, 0xE25254, 0xE15150, 0xDF4F4F, 0xDB4F4F, 0xD65051, 0xCF5151, 0xC85F5F, 0xD3A1A1, 0xE0C8C7, 0xE7E4E4, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xECD0D0, 0xDFA9AA, 0xECA2A2, 0xE36565, 0xE65151, 0xE44F4F, 0xE44D4F, 0xE04D4D, 0xDF4D4D, 0xDC4D4D, 0xDB494C, 0xD84A4A, 0xD64947, 0xD44747, 0xCB4949, 0xC34B4B, 0xD08E8E, 0xE8CCCD, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xE2B5B5, 0xE4A6A7, 0xE57778, 0xE55151, 0xE44F4F, 0xE24E4E, 0xE04D4D, 0xDE4C4C, 0xDC4B4B, 0xDB4949, 0xD74848, 0xD54747, 0xD34545, 0xD14545, 0xCF4343, 0xCC4242, 0xCB3F3F, 0xC24343, 0xB64546, 0xDCADAD, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xE2B5B5, 0xE49E9E, 0xE26667, 0xE6504E, 0xE04646, 0xDA3D3D, 0xDC4444, 0xDC4B4B, 0xDB4848, 0xD94748, 0xD54646, 0xD34344, 0xD14343, 0xCF4242, 0xCD4341, 0xC83A3A, 0xC52F31, 0xC33535, 0xC33C3C, 0xBE3D3D, 0xB53F40, 0xDCACAC, 0xD3D3D3, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xECD0D0, 0xDB8F8F, 0xE36868, 0xE24E4E, 0xDB403E, 0xE96565, 0xF7B2B2, 0xE46565, 0xD23B39, 0xD74646, 0xD44343, 0xD14343, 0xCF4242, 0xCB4040, 0xCA3F3F, 0xC43333, 0xCB4E4E, 0xE29E9E, 0xCF5B5C, 0xBA2A29, 0xBC3636, 0xB83839, 0xB13E3F, 0xE9CBCB, 0xB9B8B8, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEFECEC, 0xD69696, 0xE37B7B, 0xE04B4D, 0xDB4141, 0xE65F5F, 0xFFE7E7, 0xFFFFFF, 0xFFE9E9, 0xDC5A5A, 0xCA3333, 0xCF4242, 0xCB4040, 0xC93D3D, 0xC83E3D, 0xC23030, 0xC94848, 0xDDC0C0, 0xDEEEEC, 0xE0D0D0, 0xC75455, 0xB32828, 0xB43232, 0xB13434, 0xB75354, 0xEFECEC, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF, + 0xFFFFFF, 0xAAA9A9, 0xBEBEBE, 0xE6CAC9, 0xDB797A, 0xDF4C4C, 0xDB4141, 0xE05757, 0xFFEAEA, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFE7E8, 0xD75B5B, 0xC62E2E, 0xC93E3E, 0xC53A3A, 0xC12E2C, 0xC8494A, 0xDDC2C2, 0xDAE3E3, 0xD4D5D5, 0xD3DADA, 0xD9CBCA, 0xBB4747, 0xAD2525, 0xAC2B2C, 0xAE3233, 0xD8A4A5, 0xBFBFBF, 0xAAA9A9, 0xFFFFFF, + 0xE9E9E9, 0x807F7F, 0xEBE9E9, 0xDAA7A7, 0xDB6060, 0xDB4745, 0xD63C3C, 0xDE5758, 0xFFF2F2, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xF8E8E8, 0xD45B5B, 0xBD2828, 0xBD2B2A, 0xC54949, 0xDBC3C3, 0xDAE4E4, 0xD5D5D5, 0xD0CECE, 0xE5E8E8, 0xF4F4F4, 0xAF4949, 0xA62121, 0xA62A2A, 0xA92B2C, 0xB85755, 0xECEAEA, 0x807F7F, 0xE9E9E9, + 0xC7C6C6, 0xA2A2A2, 0xEAD9DA, 0xCF6B6B, 0xD74444, 0xD64341, 0xD34242, 0xCD3434, 0xDB6464, 0xFFEFEF, 0xFFFFFF, 0xFCFCFC, 0xF6F6F6, 0xF4FCFC, 0xF0E1E2, 0xCC5050, 0xC14040, 0xDBC3C3, 0xD8E1E1, 0xD5D4D4, 0xCFCFCF, 0xE5E8E8, 0xF4F2F2, 0xA24040, 0x990C0C, 0xA20F0F, 0xA00F0F, 0x9D0F0F, 0xA92F30, 0xE8D1D1, 0xA3A3A3, 0xC7C6C6, + 0xA9A8A8, 0xC0C0C0, 0xE1BABD, 0xCF5556, 0xD44141, 0xD23F3F, 0xCE3F3F, 0xCC3D3D, 0xC32A2C, 0xD35E5E, 0xF6EBEB, 0xFAFFFF, 0xF1F1F1, 0xEEEDED, 0xE9F0F0, 0xE6D2D2, 0xD6BDBD, 0xD3DADA, 0xCFCFCF, 0xCAC9C9, 0xE2E5E5, 0xF3F1F1, 0xA03A3A, 0x980C0C, 0xA30B0B, 0x9F0B0B, 0x9E0B0B, 0x9E0B0B, 0xA41C1C, 0xD39C9C, 0xC1C1C1, 0xA9A8A8, + 0x8F8E8E, 0xDADADA, 0xD59B9C, 0xCD4949, 0xD03D3E, 0xCE3D3C, 0xCA3C3C, 0xC83A3A, 0xC7393B, 0xBD2828, 0xCC5C5C, 0xEDE5E5, 0xEDF4F4, 0xE6E5E5, 0xDEDEDE, 0xD9DCDC, 0xD3D9D9, 0xCDCDCD, 0xC8C8C8, 0xE1E5E5, 0xF3F1F1, 0xA03F3F, 0x990C0C, 0xA40A0A, 0xA10B0B, 0xA00B0B, 0xA00B0B, 0x9F0B0B, 0xA21313, 0xC06B6B, 0xDADADA, 0x8F8E8E, + 0x7C7B7B, 0xEEEDED, 0xCB807F, 0xCC4140, 0xCA3C3C, 0xC83A3A, 0xC83A38, 0xC43838, 0xC23636, 0xC03939, 0xB72321, 0xC24A4A, 0xDECBCB, 0xDCE0E0, 0xD6D6D6, 0xD3D2D2, 0xCECDCD, 0xC9C9C9, 0xE1E2E2, 0xF2F1F1, 0xA34242, 0x990C0C, 0xA40A0A, 0xA40A0A, 0xA40A0A, 0xA30B0B, 0xA30B0B, 0xA10B0B, 0xA10E0E, 0xB04344, 0xEEEDED, 0x7C7B7B, + 0x6F6E6E, 0xFBFBFB, 0xBE5959, 0xCA3B3B, 0xC83A3A, 0xC43737, 0xC23535, 0xC03636, 0xBE3636, 0xB82323, 0xB10909, 0xA70A0A, 0xBE4949, 0xD4D6D6, 0xD1D3D3, 0xCDCDCD, 0xC8C8C8, 0xC3C4C4, 0xEDEDED, 0xB35F5F, 0x980C0C, 0xA70A0A, 0xA60A0A, 0xA60A0A, 0xA60A0A, 0xA40A0A, 0xA60A0A, 0xA40A0A, 0xA40B0B, 0xA62D2D, 0xFBFBFB, 0x6F6E6E, + 0x6F6E6E, 0xF9F9F9, 0xC16666, 0xC43838, 0xC23535, 0xC03434, 0xBE3535, 0xBC3030, 0xB41313, 0xAD0909, 0xA80A0A, 0xB31E1E, 0xD0AAAA, 0xCDD3D3, 0xCCCCCC, 0xC8C8C8, 0xC3C3C3, 0xC1C2C2, 0xBFC4C4, 0xCBB2B2, 0xB42B2B, 0xA40A0A, 0xA80A0A, 0xA80A0A, 0xA90A0A, 0xA90A0A, 0xA90A0A, 0xA90A0A, 0xA90B0B, 0xA63131, 0xFAFAFA, 0x6F6E6E, + 0x7C7B7B, 0xEBEAEB, 0xC77C7D, 0xBF3838, 0xBE3434, 0xBE3635, 0xB82A2A, 0xB00909, 0xAC0909, 0xA80A0A, 0xB11C1C, 0xD0B2B2, 0xCCD7D7, 0xCBCBCB, 0xC8C7C7, 0xC3C8C8, 0xC3C6C6, 0xC1BFBF, 0xBDBDBD, 0xBCC5C5, 0xCEB8B8, 0xB52929, 0xA80A0A, 0xAC0909, 0xAD0909, 0xAF0909, 0xAF0909, 0xAF0909, 0xB00C0C, 0xAF4747, 0xEDECEC, 0x7C7B7B, + 0x8F8E8E, 0xD7D8D9, 0xD19999, 0xBB3838, 0xBC3636, 0xB72C2C, 0xAD0909, 0xA90A0A, 0xA40A0A, 0xAF1C1C, 0xCFB1B1, 0xCBD6D6, 0xCBCCCC, 0xC7C7C7, 0xE1E4E4, 0xEEECEC, 0xB7ACAC, 0xBCC2C2, 0xBFBEBE, 0xC0C0C0, 0xC6CFCF, 0xD5C1C1, 0xB82727, 0xAC0909, 0xB20909, 0xB20909, 0xB40909, 0xB40808, 0xB50E0E, 0xBF6E6E, 0xD9D9D9, 0x8F8E8E, + 0xA9A8A8, 0xBEBEBE, 0xDCBBBA, 0xB7393A, 0xB82F2F, 0xAD0909, 0xA90A0A, 0xA60A0A, 0xAC1515, 0xCFADAD, 0xCBD6D6, 0xCACBCB, 0xC6C6C6, 0xE1E4E4, 0xEFEEEE, 0xA13838, 0xA22222, 0xB8ABAC, 0xC0C8C8, 0xC8C7C7, 0xCDCDCD, 0xD9E1E1, 0xE1CAC8, 0xBC2424, 0xB40808, 0xB90808, 0xBA0808, 0xBB0808, 0xAB0E0F, 0xD5A2A1, 0xC0C0C0, 0xA9A8A8, + 0xC7C6C6, 0xA0A1A0, 0xE4D7D6, 0xB33A3A, 0xAD1212, 0xA80A0A, 0xA40A0A, 0xAA1313, 0xCFABAB, 0xCBD6D6, 0xCACACA, 0xC6C6C6, 0xE0E4E4, 0xEFEEEE, 0xA03F3F, 0x990C0C, 0xA60A0A, 0xAB2828, 0xBFB2B2, 0xCED8D8, 0xD8D6D6, 0xE0E0E0, 0xEDF5F6, 0xEDD1D1, 0xC01C1E, 0xBE0707, 0xBF0707, 0xC00707, 0xAA2021, 0xE9D5D3, 0xA3A3A2, 0xC7C6C6, + 0xE9E9E9, 0x807F7F, 0xE5E3E3, 0xB24646, 0xA81414, 0xA40A0A, 0xA00B0B, 0xA92121, 0xCABDBD, 0xC8D0D0, 0xC5C5C5, 0xE1E3E3, 0xEFEDED, 0x9E3E3E, 0x980C0C, 0xA60A0A, 0xA80A0A, 0xA90A0A, 0xB02B2B, 0xCDC0C0, 0xE2EAEA, 0xEBEBEB, 0xF8FEFE, 0xEEEDED, 0xBD2828, 0xC40707, 0xC70908, 0xC40F0F, 0xCB8887, 0xECEBEB, 0x818080, 0xE9E9E9, + 0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xD59B9B, 0xA61C1C, 0xA10C0C, 0x9F0B0B, 0x9A0B0B, 0xA73535, 0xBEB5B5, 0xDFE6E6, 0xEFEDED, 0x9C3C3C, 0x970C0C, 0xA40A0A, 0xA60A0A, 0xA90A0A, 0xAD0909, 0xB00909, 0xB52626, 0xDECECE, 0xFBFFFF, 0xF1EEEE, 0xBA4848, 0xBC0808, 0xCD0A0A, 0xCE0B0B, 0xAB1111, 0xE0C0BE, 0xBFC0BF, 0xAAA9A9, 0xFFFFFF, + 0xFFFFFF, 0xD9D9D9, 0x8F8F8F, 0xEFECEC, 0xB14545, 0xA41616, 0x9B0B0B, 0x990C0C, 0x960C0C, 0xA23333, 0xD0B9B9, 0x9B3A39, 0x950C0C, 0xA10B0B, 0xA40A0A, 0xA70A0A, 0xAB0A0A, 0xB00909, 0xB40808, 0xB70808, 0xC22F2F, 0xE2AEAE, 0xBF4B4B, 0xBE0707, 0xD10B0B, 0xD30C0C, 0xCC1314, 0xB14848, 0xEFECEC, 0x8F8F8F, 0xD9D9D9, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB9B8B8, 0xE8CACA, 0xA32425, 0x9F1313, 0x970C0C, 0x950C0C, 0x950C0C, 0x910C0C, 0x950C0C, 0x9E0B0B, 0xA00B0B, 0xA40A0A, 0xA80A0A, 0xAD0909, 0xB20909, 0xB80808, 0xBC0808, 0xC00707, 0xBC0808, 0xC50707, 0xD30C0C, 0xD70D0D, 0xD11212, 0xA72020, 0xEBCDCD, 0xBAB9B9, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xD9A8A8, 0xA42020, 0x9B1313, 0x920C0C, 0x950C0C, 0x970C0C, 0x990C0C, 0x9E0B0B, 0xA00B0B, 0xA40A0A, 0xA90A0A, 0xB00909, 0xB40808, 0xBB0808, 0xC00707, 0xC60A0A, 0xCC0909, 0xD30C0C, 0xD80D0D, 0xD31313, 0xA81A1A, 0xDEADAE, 0xD4D4D4, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x919090, 0xE1E1E1, 0xDAA8A8, 0xA02323, 0x9C1515, 0x920D0D, 0x950C0C, 0x990C0C, 0x9E0B0B, 0xA00B0B, 0xA60A0A, 0xAC0909, 0xB20909, 0xB80808, 0xBC0808, 0xC30808, 0xC90C0C, 0xD00C0C, 0xD60D0D, 0xCF1313, 0xA92222, 0xDEAFAF, 0xE1E1E1, 0x919090, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x919090, 0xD3D3D3, 0xE8CACA, 0xB04344, 0x991717, 0x9C1111, 0x980C0C, 0x9B0B0B, 0xA00B0B, 0xA60A0A, 0xAC0909, 0xB20909, 0xBA0808, 0xBF0707, 0xC8090B, 0xCE0D0D, 0xCC1111, 0xAF1010, 0xB2494A, 0xEBCFCF, 0xD3D3D3, 0x919090, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB9B8B8, 0xEFECEC, 0xDFC0C0, 0xC47779, 0xA02122, 0x9B1212, 0xA41010, 0xA80C0C, 0xAC0A0A, 0xB40A0A, 0xB90A0A, 0xBE0D0D, 0xB10F0F, 0xA61111, 0xB85656, 0xDCADAE, 0xEFECEC, 0xB9B8B8, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8F8F, 0xBDBDBD, 0xEBE9E9, 0xE9D9D9, 0xDDB5B5, 0xCD8B8B, 0xB75A59, 0xA83937, 0xA42C2B, 0xB1494A, 0xC17171, 0xD7A2A1, 0xE8D3D3, 0xEBEAEA, 0xBFBEBE, 0x8F8F8F, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x807F7F, 0xA2A2A2, 0xC0C0C0, 0xDADADA, 0xEEEDED, 0xFBFBFB, 0xFBFBFB, 0xEEEDED, 0xDADADA, 0xC0C0C0, 0xA2A2A2, 0x807F7F, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + }; + const unsigned pic_question[] = { + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x7F7E7E, 0xA1A1A1, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA1A1A1, 0x7F7E7E, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8E8E, 0xBFBFBF, 0xEBEBEB, 0xDADADA, 0xBFC0C3, 0xAFB4C4, 0x9AA7CA, 0x7D8EC0, 0x7889BE, 0x8898C5, 0xA1AAC5, 0xB4B6C0, 0xDAD9DA, 0xEBEBEB, 0xBFBFBF, 0x8F8E8E, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB8B7B7, 0xEDEDED, 0xCACACA, 0xBEC2CF, 0x9BADDF, 0x698CE8, 0x4C75E3, 0x406BE0, 0x416DE0, 0x3F6BDD, 0x3B67D8, 0x3864D4, 0x3E68D1, 0x5375CC, 0x8A98BF, 0xC4C5CA, 0xEDEDED, 0xB8B7B7, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x908F8F, 0xD3D3D3, 0xDEDEDE, 0xC3C6CE, 0xA1B5E9, 0x6B8FED, 0x4C77E7, 0x446FE0, 0x446EDD, 0x456EDB, 0x426DD9, 0x416BD6, 0x4069D4, 0x3D67D1, 0x3C65CE, 0x3761CB, 0x305AC6, 0x3B60C3, 0x8694B8, 0xDDDDDD, 0xD3D3D3, 0x908F8F, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x908F8F, 0xE1E1E1, 0xCECECE, 0xBFC8DF, 0x819EEF, 0x537CE8, 0x416DE0, 0x446EDE, 0x456EDB, 0x416AD9, 0x3D67D6, 0x3864D3, 0x3761CF, 0x3763CD, 0x3A63CB, 0x3C64CA, 0x3B63C7, 0x3860C4, 0x335DC1, 0x2852BB, 0x5570B3, 0xC7C8CB, 0xE1E1E1, 0x908F8F, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xCECECE, 0xBAC7E9, 0x7092ED, 0x4671E2, 0x426DDE, 0x466FDD, 0x3F69D8, 0x3865D6, 0x4870D8, 0x5F82DB, 0x7290DF, 0x7290DD, 0x5E7FD6, 0x446ACB, 0x3059C2, 0x335CC1, 0x365EC1, 0x345CBC, 0x345BBA, 0x2951B5, 0x3E5EAE, 0xC5C6CB, 0xD3D3D3, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB8B7B7, 0xDEDEDE, 0xB7C0DA, 0x6E91EC, 0x426DDF, 0x456EDD, 0x456EDB, 0x3F6AD8, 0x567CDD, 0xAEC1F2, 0xEBF1FF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFAFCFF, 0xE7EAF8, 0xA3B5E3, 0x4468C2, 0x2C55B9, 0x335AB8, 0x3157B5, 0x3056B4, 0x244CAE, 0x405DA4, 0xDBDBDC, 0xB8B7B7, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xD9D9D9, 0x8F8E8E, 0xEDEDED, 0xAEB1BA, 0x7A9AED, 0x456FDF, 0x446DDB, 0x456ED9, 0x426BD7, 0x3763D1, 0xB1C3F1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFEFD, 0xFFFFFC, 0xD4DAED, 0x4466BA, 0x2B52B2, 0x2E55B0, 0x2C53AF, 0x2B51AD, 0x1F47A5, 0x6576A1, 0xEDEDED, 0x8F8E8E, 0xD9D9D9, 0xFFFFFF, + 0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xC3C3C3, 0x92A7E1, 0x537AE2, 0x406AD9, 0x446DD8, 0x426BD6, 0x3F68D3, 0x3661CE, 0xB6C5EE, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFCFCFE, 0xF8F8FA, 0xFFFFFD, 0xAAB8D9, 0x264CAC, 0x2C52AE, 0x2C51AC, 0x2B50A8, 0x2A4FA6, 0x1E429C, 0xB1B5BF, 0xBFBFBF, 0xAAA9A9, 0xFFFFFF, + 0xE9E9E9, 0x7F7E7E, 0xEBEBEB, 0x9DA3B4, 0x6B8DE8, 0x3E69D7, 0x416AD7, 0x4069D4, 0x3F68D0, 0x3D67CE, 0x345ECA, 0xB7C4EA, 0xFFFFFA, 0xC2C9DA, 0x8B9BC5, 0x778DC2, 0x99AAD1, 0xF2F3F8, 0xFEFDFF, 0xFAFAFD, 0xFAFAFC, 0xE8EAF2, 0x3859AA, 0x2A50AB, 0x2C51A8, 0x2C50A6, 0x2A4FA4, 0x244AA0, 0x506698, 0xEBEBEB, 0x7F7E7E, 0xE9E9E9, + 0xC7C6C6, 0xA1A1A1, 0xD6D6D6, 0x8498CE, 0x4E75DD, 0x3D67D4, 0x3F68D3, 0x3E66CF, 0x3D66CC, 0x3C64CA, 0x365FC6, 0x7990CF, 0x7085B8, 0x2D52AE, 0x2750B4, 0x2650B4, 0x1F48AD, 0x8499CE, 0xFDFCFA, 0xF8F8FA, 0xF9F8FC, 0xF5F6F7, 0x4865A8, 0x284FA6, 0x2C51A5, 0x2C50A3, 0x2B4FA2, 0x2B4EA1, 0x244797, 0xCBCDD2, 0xA2A2A2, 0xC7C6C6, + 0xA9A8A8, 0xC0C0C0, 0xA8AAB0, 0x5E82DA, 0x3E68D4, 0x3D67CF, 0x3E66CD, 0x3D65CB, 0x3B63C9, 0x3A61C5, 0x385FC3, 0x3057BE, 0x2B54B9, 0x335CBC, 0x345BB9, 0x345AB7, 0x274FB0, 0x5B78BF, 0xE9E9EB, 0xEDECEF, 0xF2F1F4, 0xEBEBF1, 0x31509B, 0x19419D, 0x1D429C, 0x1E429B, 0x1E4299, 0x204499, 0x173D96, 0x7F8AA3, 0xC1C1C1, 0xA9A8A8, + 0x8F8E8E, 0xDADADA, 0x8E94A5, 0x476ED5, 0x3B64CD, 0x3D66CC, 0x3C64C9, 0x3B61C6, 0x3860C4, 0x365EC2, 0x365DBF, 0x355CBB, 0x345BBA, 0x335AB7, 0x2E54B4, 0x244CAD, 0x133EA5, 0x7587B8, 0xD3D0D1, 0xD8D8DE, 0xEFEEEF, 0xBBC2D5, 0x173B91, 0x193F9A, 0x1C4199, 0x1D4199, 0x1D4198, 0x1D4197, 0x1C4096, 0x44598B, 0xDADADA, 0x8F8E8E, + 0x7C7B7B, 0xEDEDED, 0x7683A3, 0x3E67D0, 0x3B63CA, 0x3B63C7, 0x3860C4, 0x375FC2, 0x365DC0, 0x355CBE, 0x355CBA, 0x3359B7, 0x2B52B2, 0x2149AC, 0x1640A5, 0xC37A1, 0x4E68AB, 0xB5B4BA, 0xC0BFC3, 0xD1D0D6, 0xEDECEC, 0x5C72A4, 0x123893, 0x1E4299, 0x1E4299, 0x1E4298, 0x1F4298, 0x204297, 0x214498, 0x2C478A, 0xEDEDED, 0x7C7B7B, + 0x6F6E6E, 0xFBFBFB, 0x63749F, 0x3B64CC, 0x375FC4, 0x365EC3, 0x355DC0, 0x345CBE, 0x345BBB, 0x3359B7, 0x2A52B2, 0x2048AB, 0x1740A6, 0x143DA2, 0x143DA1, 0x5E74AC, 0xB1B1B7, 0xB2B1B6, 0xBABABF, 0xD6D4D6, 0x8592B5, 0x183C90, 0x20459C, 0x22469A, 0x22459A, 0x224599, 0x234699, 0x22459A, 0x23469A, 0x2B4990, 0xFBFBFB, 0x6F6E6E, + 0x6F6E6E, 0xFBFBFB, 0x617098, 0x3660C7, 0x355DBF, 0x345CBE, 0x335BBB, 0x345AB8, 0x2E54B4, 0x1F47AB, 0x1640A6, 0x143EA3, 0x153EA1, 0xE389D, 0x5F75AD, 0xC0BCBC, 0xB4B4B8, 0xB6B6BB, 0xC1C1C4, 0x6577A2, 0x1C3E92, 0x274A9E, 0x2A4B9E, 0x2A4C9E, 0x2A4C9E, 0x2A4C9E, 0x2A4BA0, 0x294BA0, 0x294A9E, 0x2F4B94, 0xFBFBFB, 0x6F6E6E, + 0x7C7B7B, 0xEDEDED, 0x6B7694, 0x335BC0, 0x335ABB, 0x3259B8, 0x3257B6, 0x2951B0, 0x1944A7, 0x153FA4, 0x153EA2, 0x143DA0, 0x133B9C, 0x1F45A0, 0xB1B6C4, 0xC4C3C6, 0xBFBFC4, 0xBEBEC4, 0x546798, 0x1D4096, 0x2C4FA2, 0x3051A2, 0x3151A2, 0x3252A3, 0x3252A4, 0x3252A5, 0x3152A5, 0x3151A5, 0x3050A5, 0x354F93, 0xEDEDED, 0x7C7B7B, + 0x8F8E8E, 0xDADADA, 0x828895, 0x2C55B7, 0x3056B7, 0x3056B5, 0x2850AE, 0x1741A5, 0x143EA2, 0x143DA0, 0x133C9D, 0x133C9B, 0xE3698, 0x3F5DA6, 0xCECED3, 0xCCCCD1, 0xD5D3D5, 0x7A87A8, 0x1E4194, 0x3253A5, 0x3454A4, 0x3655A7, 0x3756A8, 0x3756AA, 0x3856AB, 0x3856AB, 0x3756AB, 0x3555AB, 0x3554AC, 0x445993, 0xDADADA, 0x8F8E8E, + 0xA9A8A8, 0xC0C0C0, 0xA0A2A6, 0x3759AE, 0x2C54B2, 0x284FAD, 0x1740A3, 0x143EA1, 0x143D9E, 0x123B9B, 0x123B99, 0x133B99, 0xE3696, 0x4C67A8, 0xD1CED0, 0xD3D0D1, 0xD7D4D4, 0x5A6DA0, 0x2B4EA3, 0x3756A7, 0x3A59AB, 0x3B5AAD, 0x3C5AAE, 0x3D5BB0, 0x3D5BB0, 0x3C5AB0, 0x3B59B0, 0x3A57B0, 0x3554B0, 0x7380A2, 0xC1C1C1, 0xA9A8A8, + 0xC7C6C6, 0xA1A1A1, 0xD4D4D4, 0x4A629B, 0x284FAD, 0x1840A3, 0x133C9E, 0x133C9D, 0x113A9A, 0x113A98, 0x123897, 0x143C96, 0x183E97, 0x2D4F9D, 0x5E71A1, 0x6173A1, 0x6577A3, 0x3D579D, 0x3756AB, 0x3C5AAE, 0x3D5BB1, 0x3F5CB2, 0x3F5CB5, 0x3F5CB6, 0x3F5BB6, 0x3E5BB6, 0x3D5AB6, 0x3C59B6, 0x3350AC, 0xBEC2CD, 0xA2A2A2, 0xC7C6C6, + 0xE9E9E9, 0x7F7E7E, 0xEBEBEB, 0x737B8E, 0x163FA3, 0x123B9D, 0x123B9B, 0x113898, 0xF3896, 0xF3794, 0x123894, 0x173D96, 0x1F4498, 0x1F4499, 0x21469B, 0x3252A2, 0x3151A5, 0x3252AB, 0x3D5BB0, 0x3F5CB4, 0x3F5CB7, 0x3F5CB9, 0x3F5CBA, 0x3F5CBB, 0x3F5BBB, 0x3E5BBB, 0x3D5ABB, 0x3B59BB, 0x475B9E, 0xE9E9EA, 0x807F7F, 0xE9E9E9, + 0xFFFFFF, 0xAAA9A9, 0xBFBFBF, 0xB8B8B9, 0x28468D, 0xF3799, 0x113897, 0xF3694, 0xE3692, 0xF3691, 0x133892, 0x1B4096, 0x1E4298, 0x415EA3, 0x98A1B9, 0xB4B5BE, 0xB2B6C5, 0x6F83BF, 0x3A57B4, 0x3F5CB8, 0x3F5CBB, 0x3F5CBE, 0x3F5BC0, 0x3E5BC0, 0x3E5BC1, 0x3E5AC1, 0x3D5AC0, 0x3350BC, 0x9FA5B9, 0xC0C0C0, 0xAAA9A9, 0xFFFFFF, + 0xFFFFFF, 0xD9D9D9, 0x8F8E8E, 0xEDEDED, 0x6E7586, 0x93291, 0xE3693, 0xD3591, 0xD3590, 0xF3690, 0x153B92, 0x1D4194, 0x24489A, 0x97A0B9, 0xC2BFBF, 0xB7B6BA, 0xBFBCBF, 0xC7C9D1, 0x4C66B8, 0x3C59BE, 0x3F5AC0, 0x3E5AC2, 0x3D59C4, 0x3D57C5, 0x3B56C5, 0x3B56C4, 0x3855C5, 0x4F61A0, 0xECECEC, 0x8F8E8E, 0xD9D9D9, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xB0B0B0, 0xB8B7B7, 0xD9D9D9, 0x43557D, 0x5308E, 0xC348F, 0xD348E, 0x12378F, 0x193D91, 0x204496, 0x2C4E9D, 0xAFB5C5, 0xC6C4C7, 0xBEBEC3, 0xC2C2C6, 0xD4D3D6, 0x5368B6, 0x3A56C2, 0x3D59C4, 0x3B56C6, 0x3854C9, 0x3754C9, 0x3753C9, 0x3753CA, 0x364EAD, 0xCFD1D7, 0xB9B8B8, 0xB0B0B0, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0x959595, 0xD3D3D3, 0xBFC0C0, 0x384E7F, 0x7308B, 0xD348C, 0x13388E, 0x1D4093, 0x244799, 0x284A9D, 0x7788B8, 0xD4D3D4, 0xD8D6D6, 0xDDDAD9, 0xA4ABC3, 0x3852B4, 0x3B56C6, 0x3854C9, 0x3652CA, 0x3551CC, 0x3350CC, 0x334FCD, 0x344CB7, 0xB2B6C3, 0xD4D4D4, 0x959595, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x908F8F, 0xE1E1E1, 0xBFC0C1, 0x3B4E7A, 0xC338A, 0x153A8F, 0x1F4294, 0x284A9B, 0x3050A1, 0x3353A6, 0x6077B2, 0x8592BA, 0x7282B6, 0x3C54AF, 0x3855C4, 0x3854C9, 0x3551CB, 0x324FCD, 0x304BCE, 0x2E4AD1, 0x364DB0, 0xADB2C2, 0xE1E1E1, 0x908F8F, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD1D1D1, 0x908F8F, 0xD3D3D3, 0xD9D9D9, 0x5D6881, 0x234186, 0x1E4196, 0x2A4B9C, 0x3353A3, 0x3857AB, 0x3655AE, 0x3351B0, 0x3553B8, 0x3C59C3, 0x3B56C6, 0x3652CA, 0x324ECE, 0x2D4AD1, 0x2B45C9, 0x4F5FA2, 0xD0D2D8, 0xD3D3D3, 0x908F8F, 0xD1D1D1, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD8D7D7, 0x959595, 0xB8B7B7, 0xEDEDED, 0xADAFB4, 0x546181, 0x364F8E, 0x3453A2, 0x3859AD, 0x3E5BB2, 0x405CBA, 0x405CC0, 0x3E59C4, 0x3A55CA, 0x3450CE, 0x344BBD, 0x4758A0, 0xA2A7BA, 0xEDEDED, 0xB8B7B7, 0x959595, 0xD8D7D7, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xEBEBEB, 0xB0B0B0, 0x8F8E8E, 0xBFBFBF, 0xEBEBEB, 0xCECFD1, 0x888E9D, 0x5E6988, 0x4C5C89, 0x43558F, 0x435594, 0x475894, 0x596696, 0x7E86A4, 0xC6C9D1, 0xEBEBEB, 0xBFBFBF, 0x8F8E8E, 0xB0B0B0, 0xEBEBEB, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xD9D9D9, 0xAAA9A9, 0x7F7E7E, 0xA1A1A1, 0xC0C0C0, 0xDADADA, 0xEDEDED, 0xFBFBFB, 0xFBFBFB, 0xEDEDED, 0xDADADA, 0xC0C0C0, 0xA1A1A1, 0x7F7E7E, 0xAAA9A9, 0xD9D9D9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xE9E9E9, 0xC7C6C6, 0xA9A8A8, 0x8F8E8E, 0x7C7B7B, 0x6F6E6E, 0x6F6E6E, 0x7C7B7B, 0x8F8E8E, 0xA9A8A8, 0xC7C6C6, 0xE9E9E9, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + }; + + const unsigned * rawpx; + switch(ico) + { + case msgbox::icon_information: + rawpx = pic_information; + break; + case msgbox::icon_warning: + rawpx = pic_warning; + break; + case msgbox::icon_error: + rawpx = pic_error; + break; + case msgbox::icon_question: + rawpx = pic_question; + break; + default: + rawpx = nullptr; + } + if(rawpx) + { + nana::paint::pixel_buffer pxbuf(32, 32); + pxbuf.put(reinterpret_cast(rawpx), 32, 32, 32, 4*32, true); + ico_.make(32, 32); + pxbuf.paste(ico_.handle(), 0, 0); + } + } + + void _m_click(const arg_mouse& arg) + { + if(arg.window_handle == yes_) + pick_ = (no_.empty() ? msgbox::pick_ok : msgbox::pick_yes); + else if(arg.window_handle == no_) + pick_ = msgbox::pick_no; + else if(arg.window_handle == cancel_) + pick_ = msgbox::pick_cancel; + + this->close(); + } + private: + window owner_; + place place_; + nana::paint::graphics ico_; + nana::label text_; + nana::button yes_, no_, cancel_; + msgbox::pick_t pick_; + }; +#endif + + //class msgbox + msgbox::msgbox() + : wd_(nullptr), button_(ok), icon_(icon_none) + {} + + msgbox::msgbox(const msgbox& rhs) + : wd_(rhs.wd_), title_(rhs.title_), button_(rhs.button_), icon_(rhs.icon_) + { + sstream_<(nana::charset(str)); +#else + sstream_<(nana::charset(str));; +#else + sstream_<(API::root(wd_)), static_cast(nana::charset(sstream_.str())).c_str(), title_.c_str(), type); + #else + int bt = ::MessageBoxA(reinterpret_cast(API::root(wd_), sstream_.str().c_str(), title_.c_str(), type); + #endif + switch(bt) + { + case IDOK: + return pick_ok; + case IDYES: + return pick_yes; + case IDNO: + return pick_no; + case IDCANCEL: + return pick_cancel; + } + + return pick_yes; +#elif defined(NANA_X11) + msgbox_window box(wd_, title_, button_, icon_); + box.prompt(nana::charset(sstream_.str())); + return box.pick(); +#endif + return pick_yes; + } + + //end class msgbox +} diff --git a/source/gui/notifier.cpp b/source/gui/notifier.cpp new file mode 100644 index 00000000..c0567bc5 --- /dev/null +++ b/source/gui/notifier.cpp @@ -0,0 +1,360 @@ +/* +* Implementation of Notifier +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2014 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/gui/notifier.cpp +*/ +#include +#include +#include +#include + +#include +#include +#include + +#if defined(NANA_WINDOWS) +#include +#elif defined(NANA_LINUX) +#include PLATFORM_SPEC_HPP +#include +#include +#endif + +namespace nana +{ + typedef std::lock_guard lock_guard; + + struct notifier::implement + { + nana::timer ani_timer; + native_window_type native_handle; + window handle; + event_handle evt_destroy; + unsigned short id; + detail::notifier_events events; + bool icon_added = false; + std::size_t play_index; +#if defined(NANA_WINDOWS) + HICON icon_handle = nullptr; + std::vector icons; + + void set_icon(HICON icon) + { + if (icon_handle) + { + NOTIFYICONDATA icon_data; + memset(&icon_data, 0, sizeof icon_data); + icon_data.cbSize = sizeof icon_data; + icon_data.hWnd = reinterpret_cast(native_handle); + icon_data.uID = id; + icon_data.uFlags = NIF_MESSAGE | NIF_ICON; + icon_data.uCallbackMessage = nana::detail::messages::tray; + icon_data.hIcon = icon; + + ::Shell_NotifyIcon(icon_added ? NIM_MODIFY : NIM_ADD, &icon_data); + icon_added = true; + } + } +#endif + }; + + arg_notifier::operator nana::arg_mouse() const + { + arg_mouse arg; + arg.evt_code = evt_code; + arg.ctrl = false; + arg.shift = false; + arg.left_button = left_button; + arg.mid_button = mid_button; + arg.right_button = right_button; + arg.pos = pos; + arg.window_handle = (notifier_ptr ? notifier_ptr->handle() : nullptr); + return arg; + } + + class notifications + { + struct notifier_data + { + ::nana::notifier * notifier_ptr; + detail::notifier_events* evt_ptr; + }; + + struct window_notifiers + { + std::unordered_map idtable; + }; + public: + static notifications& instance() + { + static notifications obj; + return obj; + } + + unsigned short register_wd(::nana::notifier* ntf_ptr, native_window_type native_handle, detail::notifier_events* evt_ptr) + { + lock_guard lock(mutex_); + auto i = wd_table_.find(native_handle); + if (i == wd_table_.end()) + { + auto & data = wd_table_[native_handle].idtable[0]; + data.notifier_ptr = ntf_ptr; + data.evt_ptr = evt_ptr; + return 0; + } + + auto & idtable = i->second.idtable; + auto id = static_cast(idtable.size()); + + const auto orig_id = id; + while (idtable.count(id) != 0) + { + if (orig_id == ++id) + throw std::runtime_error("Full"); + } + + auto & data = idtable[id]; + data.notifier_ptr = ntf_ptr; + data.evt_ptr = evt_ptr; + return id; + } + + void cancel(native_window_type wd, unsigned short id) + { + lock_guard lock(mutex_); + auto i_wd = wd_table_.find(wd); + if (i_wd == wd_table_.end()) + return; + + auto & idtable = i_wd->second.idtable; + auto i_id = idtable.find(id); + if (i_id == idtable.end()) + return; + + idtable.erase(i_id); + if (idtable.empty()) + wd_table_.erase(i_wd); + } + + void emit(native_window_type wd, unsigned short id, const arg_notifier& arg_basic) + { + lock_guard lock(mutex_); + auto i_wd = wd_table_.find(wd); + if (i_wd == wd_table_.end()) + return; + + auto & idtable = i_wd->second.idtable; + auto i_id = idtable.find(id); + if (i_id == idtable.end()) + return; + + auto arg = arg_basic; + + arg.notifier_ptr = i_id->second.notifier_ptr; + + auto evt_ptr = i_id->second.evt_ptr; + switch (arg.evt_code) + { + case event_code::mouse_down: + evt_ptr->mouse_down.emit(arg); + break; + case event_code::mouse_up: + evt_ptr->mouse_up.emit(arg); + break; + case event_code::mouse_leave: + evt_ptr->mouse_leave.emit(arg); + break; + case event_code::mouse_move: + evt_ptr->mouse_move.emit(arg); + break; + case event_code::dbl_click: + evt_ptr->dbl_click.emit(arg); + break; + default: + break; + } + } + private: + mutable std::recursive_mutex mutex_; + std::unordered_map wd_table_; + }; + +#if defined(NANA_WINDOWS) + void notifications_window_proc(HWND wd, WPARAM wparam, LPARAM lparam) + { + arg_notifier arg; + switch (lparam) + { + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + arg.evt_code = event_code::dbl_click; + arg.left_button = (lparam == WM_LBUTTONDBLCLK); + arg.mid_button = (lparam == WM_MBUTTONDBLCLK); + arg.right_button = (lparam == WM_RBUTTONDBLCLK); + break; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + arg.evt_code = event_code::mouse_down; + arg.left_button = (lparam == WM_LBUTTONDOWN); + arg.mid_button = (lparam == WM_MBUTTONDOWN); + arg.right_button = (lparam == WM_RBUTTONDOWN); + break; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + arg.evt_code = event_code::mouse_up; + arg.left_button = (lparam == WM_LBUTTONUP); + arg.mid_button = (lparam == WM_MBUTTONUP); + arg.right_button = (lparam == WM_RBUTTONUP); + break; + case WM_MOUSEMOVE: + case WM_MOUSELEAVE: + arg.evt_code = (WM_MOUSEMOVE == lparam ? event_code::mouse_move : event_code::mouse_leave); + arg.left_button = false; + arg.mid_button = false; + arg.right_button = false; + break; + default: + return; + } + + ::POINT pos; + ::GetCursorPos(&pos); + arg.pos.x = pos.x; + arg.pos.y = pos.y; + + notifications::instance().emit(reinterpret_cast(wd), static_cast(wparam), arg); + } +#endif + + typedef ::nana::detail::bedrock bedrock; + //class notifier + notifier::notifier(window wd) + : impl_(new implement) + { + impl_->ani_timer.elapse([this] + { +#if defined(NANA_WINDOWS) + if (impl_->play_index >= impl_->icons.size()) + impl_->play_index = 0; + + auto ico = impl_->icons[impl_->play_index++]; + impl_->set_icon(ico); +#endif + }); + + auto & brock = bedrock::instance(); + impl_->handle = wd; + impl_->native_handle = brock.root(reinterpret_cast(wd)); + impl_->evt_destroy = API::events(wd).destroy([this] + { + close(); + }); + impl_->id = notifications::instance().register_wd(this, impl_->native_handle, &impl_->events); + } + + notifier::~notifier() + { + close(); + delete impl_; + } + + void notifier::close() + { + if (nullptr == impl_->native_handle) + return; + +#if defined(NANA_WINDOWS) + NOTIFYICONDATA icon_data; + memset(&icon_data, 0, sizeof icon_data); + icon_data.cbSize = sizeof icon_data; + icon_data.hWnd = reinterpret_cast(impl_->native_handle); + icon_data.uID = impl_->id; + ::Shell_NotifyIcon(NIM_DELETE, &icon_data); + + if (impl_->icon_handle) + ::DestroyIcon(impl_->icon_handle); + + for (auto handle : impl_->icons) + ::DestroyIcon(handle); +#endif + API::umake_event(impl_->evt_destroy); + notifications::instance().cancel(impl_->native_handle, impl_->id); + impl_->native_handle = nullptr; + } + + void notifier::text(const nana::string& str) + { +#if defined(NANA_WINDOWS) + NOTIFYICONDATA icon_data; + memset(&icon_data, 0, sizeof icon_data); + icon_data.cbSize = sizeof icon_data; + icon_data.hWnd = reinterpret_cast(impl_->native_handle); + icon_data.uID = impl_->id; + icon_data.uFlags = NIF_MESSAGE | NIF_TIP; + icon_data.uCallbackMessage = nana::detail::messages::tray; + + strcpy(icon_data.szTip, str.data()); + + ::Shell_NotifyIcon(impl_->icon_added ? NIM_MODIFY : NIM_ADD, &icon_data); + impl_->icon_added = true; +#endif + } + + void notifier::icon(const nana::string& icon_file) + { +#if defined(NANA_WINDOWS) + auto pre_icon = impl_->icon_handle; + auto ico = (HICON)::LoadImage(0, icon_file.data(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + if (ico) + { + impl_->icon_handle = ico; + impl_->ani_timer.stop(); + impl_->play_index = 0; + impl_->set_icon(impl_->icon_handle); + ::DestroyIcon(pre_icon); + } +#endif + } + + void notifier::insert_icon(const nana::string& icon_file) + { +#if defined(NANA_WINDOWS) + auto icon = (HICON)::LoadImage(0, icon_file.data(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + impl_->icons.push_back(icon); +#endif + } + + void notifier::period(unsigned ms) + { +#if defined(NANA_WINDOWS) + if (ms && impl_->icons.size()) + { + ms /= static_cast(impl_->icons.size()); + impl_->ani_timer.interval(ms < 16 ? 16 : ms); + impl_->ani_timer.start(); + } + else + impl_->ani_timer.stop(); +#endif + } + + detail::notifier_events& notifier::events() + { + return impl_->events; + } + + window notifier::handle() const + { + return impl_->handle; + } + //end notifier +} diff --git a/source/gui/place.cpp b/source/gui/place.cpp new file mode 100644 index 00000000..42f3befd --- /dev/null +++ b/source/gui/place.cpp @@ -0,0 +1,2219 @@ +/* + * An Implementation of Place for Layout + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/place.cpp + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace nana +{ + namespace place_parts + { + void check_field_name(const char* name) + { + //check the name + if (*name && (*name != '_' && !(('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z')))) + throw std::invalid_argument("place.field: bad field name"); + } + + class splitter_interface + { + public: + virtual ~splitter_interface(){} + }; + + class splitter_dtrigger + : public drawer_trigger + { + }; + + template + class splitter + : public widget_object ::type, splitter_dtrigger>, + public splitter_interface + { + }; + + //number_t is used for storing a number type variable + //such as integer, real and percent. Essentially, percent is a typo of real. + class number_t + { + public: + enum class kind{ none, integer, real, percent }; + + number_t() + : kind_(kind::none) + { + value_.integer = 0; + } + + void reset() + { + kind_ = kind::none; + value_.integer = 0; + } + + bool is_negative() const + { + switch (kind_) + { + case kind::integer: + return (value_.integer < 0); + case kind::real: + case kind::percent: + return (value_.real < 0); + default: + break; + } + return false; + } + + bool is_none() const + { + return (kind::none == kind_); + } + + bool is_not_none() const + { + return (kind::none != kind_); + } + + kind kind_of() const + { + return kind_; + } + + double get_value(int ref_percent) const + { + switch (kind_) + { + case kind::integer: + return value_.integer; + case kind::real: + return value_.real; + case kind::percent: + return value_.real * ref_percent; + default: + break; + } + return 0; + } + + int integer() const + { + if (kind::integer == kind_) + return value_.integer; + return static_cast(value_.real); + } + + double real() const + { + if (kind::integer == kind_) + return value_.integer; + return value_.real; + } + + void assign(int i) + { + kind_ = kind::integer; + value_.integer = i; + } + + void assign(double d) + { + kind_ = kind::real; + value_.real = d; + } + + void assign_percent(double d) + { + kind_ = kind::percent; + value_.real = d / 100; + } + private: + kind kind_; + union valueset + { + int integer; + double real; + }value_; + };//end class number_t + + class margin + { + public: + margin& operator=(margin&& rhs) + { + if (this != &rhs) + { + all_edges_ = rhs.all_edges_; + margins_ = std::move(rhs.margins_); + } + return *this; + } + + void clear() + { + all_edges_ = true; + margins_.clear(); + } + + void push(const number_t& v) + { + margins_.emplace_back(v); + } + + void set_value(const number_t& v) + { + clear(); + margins_.emplace_back(v); + } + + void set_array(const std::vector& v) + { + all_edges_ = false; + margins_ = v; + } + + nana::rectangle area(const ::nana::rectangle& field_area) const + { + if (margins_.empty()) + return field_area; + + auto r = field_area; + if (all_edges_) + { + auto px = static_cast(margins_.back().get_value(static_cast(r.width))); + const auto dbl_px = static_cast(px << 1); + r.x += px; + r.width = (r.width < dbl_px ? 0 : r.width - dbl_px); + + r.y += px; + r.height = (r.height < dbl_px ? 0 : r.height - dbl_px); + } + else + { + int il{ -1 }, ir{ -1 }, it{ -1 }, ib{ -1 }; //index of four corners in margin + switch (margins_.size()) + { + case 0: break; + case 1: //top + it = 0; + break; + case 2://top,bottom and left,right + it = ib = 0; + il = ir = 1; + break; + default: + il = 3; //left + case 3: //top, right, bottom + it = 0; + ir = 1; + ib = 2; + } + + typedef decltype(r.height) px_type; + auto calc = [](px_type a, px_type b) + { + return (a > b ? a - b : 0); + }; + + if (0 == it) //top + { + auto px = static_cast(margins_[it].get_value(static_cast(field_area.height))); + r.y += px; + r.height = calc(r.height, static_cast(px)); + } + + if (-1 != ib) //bottom + { + auto px = static_cast(margins_[ib].get_value(static_cast(field_area.height))); + r.height = calc(r.height, static_cast(px)); + } + + if (-1 != il) //left + { + auto px = static_cast(margins_[il].get_value(static_cast(field_area.width))); + r.x += px; + r.width = calc(r.width, static_cast(px)); + } + + if (-1 != ir) //right + { + auto px = static_cast(margins_[ir].get_value(static_cast(field_area.width))); + r.width = calc(r.width, static_cast(px)); + } + } + return r; + } + private: + bool all_edges_ = true; + std::vector margins_; + };//end class margin + + class repeated_array + { + public: + + //A workaround for VC2013, becuase it does not generated an implicit declared move-constructor as defaulted. + repeated_array() = default; + + repeated_array(repeated_array && other) + : repeated_{other.repeated_}, + values_(std::move(other.values_)) + { + } + + repeated_array& operator=(repeated_array&& other) + { + if(this != &other) + { + repeated_ = other.repeated_; + other.repeated_ = false; + values_ = std::move(other.values_); + } + return *this; + } + + void assign(std::vector&& c) + { + values_ = std::move(c); + } + + bool empty() const + { + return values_.empty(); + } + + void reset() + { + repeated_ = false; + values_.clear(); + } + + void repeated() + { + repeated_ = true; + } + + void push(const number_t& n) + { + values_.emplace_back(n); + } + + number_t at(std::size_t pos) const + { + if (values_.empty()) + return{}; + + if (repeated_) + pos %= values_.size(); + else if (pos >= values_.size()) + return{}; + + return values_[pos]; + } + private: + bool repeated_ = false; + std::vector values_; + }; + }//end namespace place_parts + + typedef place_parts::number_t number_t; + typedef place_parts::repeated_array repeated_array; + + namespace place_parts + { + class tokenizer + { + public: + enum class token + { + div_start, div_end, splitter, + identifier, vert, grid, number, array, reparray, + weight, gap, margin, arrange, variable, repeated, min_px, max_px, + collapse, parameters, + equal, + eof, error + }; + + tokenizer(const char* p) + : divstr_(p), sp_(p) + {} + + const std::string& idstr() const + { + return idstr_; + } + + number_t number() const + { + return number_; + } + + std::vector& array() + { + return array_; + } + + repeated_array&& reparray() + { + return std::move(reparray_); + } + + std::vector& parameters() + { + return parameters_; + } + + token read() + { + sp_ = _m_eat_whitespace(sp_); + + std::size_t readbytes = 0; + switch (*sp_) + { + case '\0': + return token::eof; + case '|': + ++sp_; + readbytes = _m_number(sp_, false); + sp_ += readbytes; + return token::splitter; + case '=': + ++sp_; + return token::equal; + case '<': + ++sp_; + return token::div_start; + case '>': + ++sp_; + return token::div_end; + case '[': + array_.clear(); + sp_ = _m_eat_whitespace(sp_ + 1); + if (*sp_ == ']') + { + ++sp_; + return token::array; + } + + { + //When search the repeated. + bool repeated = false; + + while (true) + { + sp_ = _m_eat_whitespace(sp_); + auto tk = read(); + if (token::number != tk && token::variable != tk && token::repeated != tk) + _m_throw_error("invalid array element"); + + if (!repeated) + { + switch (tk) + { + case token::number: + array_.push_back(number_); + break; + case token::variable: + array_.push_back({}); + break; + default: + repeated = true; + reparray_.repeated(); + reparray_.assign(std::move(array_)); + } + } + + sp_ = _m_eat_whitespace(sp_); + char ch = *sp_++; + + if (ch == ']') + return (repeated ? token::reparray : token::array); + + if (ch != ',') + _m_throw_error("invalid array"); + } + } + break; + case '(': + parameters_.clear(); + sp_ = _m_eat_whitespace(sp_ + 1); + if (*sp_ == ')') + { + ++sp_; + return token::parameters; + } + + while (true) + { + if (token::number == read()) + parameters_.push_back(number_); + else + _m_throw_error("invalid parameter."); + + sp_ = _m_eat_whitespace(sp_); + char ch = *sp_++; + + if (ch == ')') + return token::parameters; + + if (ch != ',') + _m_throw_error("invalid parameter."); + } + break; + case '.': case '-': + if (*sp_ == '-') + { + readbytes = _m_number(sp_ + 1, true); + if (readbytes) + ++readbytes; + } + else + readbytes = _m_number(sp_, false); + + if (readbytes) + { + sp_ += readbytes; + return token::number; + } + else + _m_throw_error(*sp_); + break; + default: + if ('0' <= *sp_ && *sp_ <= '9') + { + readbytes = _m_number(sp_, false); + if (readbytes) + { + sp_ += readbytes; + return token::number; + } + } + break; + } + + if ('_' == *sp_ || isalpha(*sp_)) + { + const char * idstart = sp_++; + + while ('_' == *sp_ || isalpha(*sp_) || isalnum(*sp_)) + ++sp_; + + idstr_.assign(idstart, sp_); + + if ("weight" == idstr_ || "min" == idstr_ || "max" == idstr_) + { + auto ch = idstr_[1]; + _m_attr_number_value(); + switch (ch) + { + case 'e': return token::weight; + case 'i': return token::min_px; + case 'a': return token::max_px; + } + } + else if ("vertical" == idstr_ || "vert" == idstr_) + return token::vert; + else if ("variable" == idstr_ || "repeated" == idstr_) + return ('v' == idstr_[0] ? token::variable : token::repeated); + else if ("arrange" == idstr_ || "gap" == idstr_) + { + auto ch = idstr_[0]; + _m_attr_reparray(); + return ('a' == ch ? token::arrange : token::gap); + } + else if ("grid" == idstr_ || "margin" == idstr_) + { + auto idstr = idstr_; + if (token::equal != read()) + _m_throw_error("an equal sign is required after '" + idstr + "'"); + + return ('g' == idstr[0] ? token::grid : token::margin); + } + else if ("collapse" == idstr_) + { + if (token::parameters != read()) + _m_throw_error("a parameter list is required after 'collapse'"); + return token::collapse; + } + return token::identifier; + } + + std::string err = "an invalid character '"; + err += *sp_; + err += "'"; + + _m_throw_error(err); + return token::error; //Useless, just for syntax correction. + } + private: + void _m_throw_error(char err_char) + { + std::stringstream ss; + ss << "place: invalid character '" << err_char << "' at " << static_cast(sp_ - divstr_); + throw std::runtime_error(ss.str()); + } + + void _m_attr_number_value() + { + if (token::equal != read()) + _m_throw_error("an equal sign is required after '" + idstr_ + "'"); + + const char* p = sp_; + for (; *p == ' '; ++p); + + auto neg_ptr = p; + if ('-' == *p) + ++p; + + auto len = _m_number(p, neg_ptr != p); + if (0 == len) + _m_throw_error("the '" + idstr_ + "' requires a number(integer or real or percent)"); + + sp_ += len + (p - sp_); + } + + void _m_attr_reparray() + { + auto idstr = idstr_; + if (token::equal != read()) + _m_throw_error("an equal sign is required after '" + idstr + "'"); + + const char* p = sp_; + for (; *p == ' ' || *p == '\t'; ++p); + + reparray_.reset(); + auto tk = read(); + switch (tk) + { + case token::number: + reparray_.push(number()); + reparray_.repeated(); + break; + case token::array: + reparray_.assign(std::move(array_)); + break; + case token::reparray: + break; + default: + _m_throw_error("a (repeated) array is required after '" + idstr + "'"); + } + } + + void _m_throw_error(const std::string& err) + { + std::stringstream ss; + ss << "place: " << err << " at " << static_cast(sp_ - divstr_); + throw std::runtime_error(ss.str()); + } + + const char* _m_eat_whitespace(const char* sp) + { + while (*sp && !isgraph(*sp)) + ++sp; + return sp; + } + + std::size_t _m_number(const char* sp, bool negative) + { + const char* allstart = sp; + sp = _m_eat_whitespace(sp); + + number_.assign(0); + + bool gotcha = false; + int integer = 0; + double real = 0; + //read the integral part. + const char* istart = sp; + while ('0' <= *sp && *sp <= '9') + { + integer = integer * 10 + (*sp - '0'); + ++sp; + } + const char* iend = sp; + + if ('.' == *sp) + { + double div = 1; + const char* rstart = ++sp; + while ('0' <= *sp && *sp <= '9') + { + real += (*sp - '0') / (div *= 10); + ++sp; + } + + if (rstart != sp) + { + real += integer; + number_.assign(negative ? -real : real); + gotcha = true; + } + } + else if (istart != iend) + { + number_.assign(negative ? -integer : integer); + gotcha = true; + } + + if (gotcha) + { + for (; *sp == ' ' || *sp == '\t'; ++sp); + if ('%' == *sp) + { + if (number_t::kind::integer == number_.kind_of()) + number_.assign_percent(number_.integer()); + return sp - allstart + 1; + } + return sp - allstart; + } + number_.reset(); + return 0; + } + private: + const char* divstr_; + const char* sp_; + std::string idstr_; + number_t number_; + std::vector array_; + repeated_array reparray_; + std::vector parameters_; + }; //end class tokenizer + } + + + //struct implement + struct place::implement + { + class field_impl; + class division; + class div_arrange; + class div_grid; + class div_splitter; + + window window_handle{nullptr}; + event_handle event_size_handle{nullptr}; + std::unique_ptr root_division; + std::map fields; + + //The following functions are defined behind the definition of class division. + //because the class division here is an incomplete type. + ~implement(); + static division * search_div_name(division* start, const std::string&); + std::unique_ptr scan_div(place_parts::tokenizer&); + }; //end struct implement + + class place::implement::field_impl + : public place::field_interface + { + public: + struct element_t + { + window handle; + event_handle evt_destroy; + + element_t(window h, event_handle event_destroy) + :handle(h), evt_destroy(event_destroy) + {} + }; + + field_impl(place * p) + : place_ptr_(p) + {} + + ~field_impl() + { + for (auto & e : elements) + API::umake_event(e.evt_destroy); + + for (auto & e : fastened) + API::umake_event(e.evt_destroy); + } + + void visible(bool vsb) + { + for (auto & e : elements) + API::show_window(e.handle, vsb); + + for (auto & e : fastened) + API::show_window(e.handle, vsb); + } + private: + //The defintion is moved after the definition of class division + template + void _m_for_each(division*, Function); + + //Listen to destroy of a window + //It will delete the element and recollocate when the window destroyed. + event_handle _m_make_destroy(window wd) + { + return API::events(wd).destroy.connect([this](const arg_destroy& arg) + { + for (auto i = elements.begin(), end = elements.end(); i != end; ++i) + { + if (arg.window_handle == i->handle) + { + elements.erase(i); + break; + } + } + place_ptr_->collocate(); + }); + } + + field_interface& operator<<(const nana::char_t* label_text) override + { + return static_cast(this)->operator<<(agent