Merge branch 'hotfixes-1.0.2' into develop
Conflicts: include/nana/gui/detail/basic_window.hpp include/nana/gui/widgets/listbox.hpp source/gui/detail/linux_X11/bedrock.cpp source/gui/detail/win32/bedrock.cpp source/gui/detail/window_layout.cpp source/gui/detail/window_manager.cpp source/gui/widgets/listbox.cpp source/gui/widgets/toolbar.cpp
This commit is contained in:
@@ -8,7 +8,8 @@ namespace nana{ namespace audio
|
||||
//class audio_stream
|
||||
bool audio_stream::open(const nana::string& file)
|
||||
{
|
||||
fs_.open(static_cast<std::string>(nana::charset(file)), std::ios::binary);
|
||||
std::string fname{nana::charset(file)};//static_cast<std::string>()
|
||||
fs_.open(fname, std::ios::binary);
|
||||
if(fs_)
|
||||
{
|
||||
wave_spec::master_riff_chunk riff;
|
||||
|
||||
@@ -799,7 +799,7 @@ namespace nana
|
||||
switch(utf_x_)
|
||||
{
|
||||
case unicode::utf8:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
strbuf = detail::utf8_to_utf16(data_, true);
|
||||
detail::put_utf16char(strbuf, 0, true);
|
||||
#else
|
||||
@@ -808,7 +808,7 @@ namespace nana
|
||||
#endif
|
||||
break;
|
||||
case unicode::utf16:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
strbuf = data_;
|
||||
detail::put_utf16char(strbuf, 0, true);
|
||||
#else
|
||||
@@ -817,7 +817,7 @@ namespace nana
|
||||
#endif
|
||||
break;
|
||||
case unicode::utf32:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
strbuf = detail::utf32_to_utf16(data_);
|
||||
detail::put_utf16char(strbuf, 0, true);
|
||||
#else
|
||||
@@ -907,21 +907,21 @@ namespace nana
|
||||
switch(utf_x_)
|
||||
{
|
||||
case unicode::utf8:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
bytes = detail::utf8_to_utf16(data_, true);
|
||||
#else
|
||||
bytes = detail::utf8_to_utf32(data_, true);
|
||||
#endif
|
||||
break;
|
||||
case unicode::utf16:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
bytes = data_;
|
||||
#else
|
||||
bytes = detail::utf16_to_utf32(data_);
|
||||
#endif
|
||||
break;
|
||||
case unicode::utf32:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
bytes = detail::utf32_to_utf16(data_);
|
||||
#else
|
||||
bytes = data_;
|
||||
@@ -984,19 +984,19 @@ namespace nana
|
||||
switch(encoding)
|
||||
{
|
||||
case unicode::utf8:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
return detail::utf16_to_utf8(std::string(reinterpret_cast<const char*>(data_.c_str()), data_.size() * sizeof(wchar_t)));
|
||||
#else
|
||||
return detail::utf32_to_utf8(std::string(reinterpret_cast<const char*>(data_.c_str()), data_.size() * sizeof(wchar_t)));
|
||||
#endif
|
||||
case unicode::utf16:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
return std::string(reinterpret_cast<const char*>(data_.c_str()), data_.size() * sizeof(wchar_t));
|
||||
#else
|
||||
return detail::utf32_to_utf16(std::string(reinterpret_cast<const char*>(data_.c_str()), data_.size() * sizeof(wchar_t)));
|
||||
#endif
|
||||
case unicode::utf32:
|
||||
#if defined(NANA_MINGW)
|
||||
#if defined(NANA_WINDOWS)
|
||||
return detail::utf16_to_utf32(std::string(reinterpret_cast<const char*>(data_.c_str()), data_.size() * sizeof(wchar_t)));
|
||||
#else
|
||||
return std::string(reinterpret_cast<const char*>(data_.c_str()), data_.size() * sizeof(wchar_t));
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace detail
|
||||
bool conf::open(const char* file)
|
||||
{
|
||||
ifs_.open(file);
|
||||
return static_cast<bool>(ifs_ != 0);
|
||||
return static_cast<bool>(ifs_);
|
||||
}
|
||||
|
||||
std::string conf::value(const char* key)
|
||||
|
||||
444
source/filesystem/filesystem.cpp
Normal file
444
source/filesystem/filesystem.cpp
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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/filesystem.cpp
|
||||
* @description:
|
||||
* provide some interface for file managment
|
||||
*/
|
||||
|
||||
#include <nana/filesystem/filesystem.hpp>
|
||||
#include <vector>
|
||||
#if defined(NANA_WINDOWS)
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(NANA_MINGW)
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0500
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <shlobj.h>
|
||||
#include <nana/datetime.hpp>
|
||||
#elif defined(NANA_LINUX)
|
||||
#include <nana/charset.hpp>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace nana {
|
||||
namespace experimental
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
file_type path::what() const
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
unsigned long attr = ::GetFileAttributes(text_.c_str());
|
||||
if (INVALID_FILE_ATTRIBUTES == attr)
|
||||
return file_type::not_found; //??
|
||||
|
||||
if (FILE_ATTRIBUTE_DIRECTORY & attr)
|
||||
return file_type::directory;
|
||||
|
||||
return file_type::regular;
|
||||
#elif defined(NANA_LINUX)
|
||||
struct stat sta;
|
||||
if (-1 == ::stat(text_.c_str(), &sta))
|
||||
return file_type::not_found; //??
|
||||
|
||||
if ((S_IFDIR & sta.st_mode) == S_IFDIR)
|
||||
return file_type::directory;
|
||||
|
||||
if ((S_IFREG & sta.st_mode) == S_IFREG)
|
||||
return file_type::regular;
|
||||
|
||||
return file_type::none;
|
||||
#endif
|
||||
}
|
||||
|
||||
nana::string path::filename() 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<directory_iterator::value_type> files;
|
||||
nana::string path = dir;
|
||||
path += '\\';
|
||||
|
||||
std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files));
|
||||
|
||||
for (auto & f : files)
|
||||
{
|
||||
if (f.attr.directory)
|
||||
rm_dir_recursive(path + f.path().filename());
|
||||
else
|
||||
rmfile((path + f.path().filename()).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<std::string>(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.size = li.QuadPart;
|
||||
attr.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<std::string>(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;
|
||||
}
|
||||
|
||||
uintmax_t file_size(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<GetFileSizeEx_fptr_t>(::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<std::string>(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<std::string>(nana::charset(file)).c_str(), &attr))
|
||||
{
|
||||
t = *(::localtime(&attr.st_ctime));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool create_directory(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<std::string>(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();
|
||||
}
|
||||
|
||||
path current_path()
|
||||
{
|
||||
#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 experimental
|
||||
}//end namespace nana
|
||||
@@ -7,7 +7,7 @@ namespace nana
|
||||
{
|
||||
//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)
|
||||
:wd_(wd), size_(width, height), visible_state_(visible_state::invisible), out_of_range_(false)
|
||||
{}
|
||||
|
||||
caret_descriptor::~caret_descriptor()
|
||||
@@ -22,8 +22,9 @@ namespace nana
|
||||
if(active)
|
||||
{
|
||||
native_interface::caret_create(wd_->root, size_);
|
||||
real_visible_state_ = false;
|
||||
visible_ = false;
|
||||
//real_visible_state_ = false;
|
||||
//visible_ = false;
|
||||
visible_state_ = visible_state::invisible;
|
||||
this->position(point_.x, point_.y);
|
||||
}
|
||||
else
|
||||
@@ -76,19 +77,36 @@ namespace nana
|
||||
return point_;
|
||||
}
|
||||
|
||||
void caret_descriptor::visible(bool isshow)
|
||||
void caret_descriptor::visible(bool is_show)
|
||||
{
|
||||
if(visible_ != isshow)
|
||||
/*
|
||||
if(visible_ != isshow) //deprecated
|
||||
{
|
||||
visible_ = isshow;
|
||||
if(visible_ == false || false == out_of_range_)
|
||||
_m_visible(isshow);
|
||||
}
|
||||
*/
|
||||
|
||||
auto pre_displayed = (visible_state::displayed == visible_state_);
|
||||
|
||||
if (is_show)
|
||||
{
|
||||
visible_state_ = visible_state::visible;
|
||||
if (wd_->displayed() && (! out_of_range_))
|
||||
visible_state_ = visible_state::displayed;
|
||||
}
|
||||
else
|
||||
visible_state_ = visible_state::invisible;
|
||||
|
||||
if (pre_displayed != (visible_state::displayed == visible_state_))
|
||||
native_interface::caret_visible(wd_->root, !pre_displayed);
|
||||
}
|
||||
|
||||
bool caret_descriptor::visible() const
|
||||
{
|
||||
return visible_;
|
||||
//return visible_; //deprecated
|
||||
return (visible_state::invisible != visible_state_);
|
||||
}
|
||||
|
||||
nana::size caret_descriptor::size() const
|
||||
@@ -101,17 +119,21 @@ namespace nana
|
||||
size_ = s;
|
||||
update();
|
||||
|
||||
if(visible_) this->visible(true);
|
||||
//if(visible_) this->visible(true); //deprecated
|
||||
if (visible_state::invisible != visible_state_)
|
||||
visible(true);
|
||||
}
|
||||
|
||||
/*
|
||||
void caret_descriptor::_m_visible(bool isshow)
|
||||
{
|
||||
if(real_visible_state_ != isshow)
|
||||
if(real_visible_state_ != isshow) //deprecated
|
||||
{
|
||||
real_visible_state_ = isshow;
|
||||
native_interface::caret_visible(wd_->root, isshow);
|
||||
native_interface::caret_visible(wd_->root, isshow && wd_->displayed());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void caret_descriptor::update()
|
||||
{
|
||||
@@ -138,8 +160,10 @@ namespace nana
|
||||
{
|
||||
out_of_range_ = true;
|
||||
|
||||
if(visible_)
|
||||
_m_visible(false);
|
||||
//if(visible_)
|
||||
// _m_visible(false); //deprecated
|
||||
if (visible_state::invisible != visible_state_)
|
||||
visible(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -164,19 +188,27 @@ namespace nana
|
||||
|
||||
if(out_of_range_)
|
||||
{
|
||||
if(paint_size_ == size)
|
||||
_m_visible(true);
|
||||
//if(paint_size_ == size) //deprecated
|
||||
// _m_visible(true);
|
||||
if (paint_size_ == size)
|
||||
visible(true);
|
||||
|
||||
out_of_range_ = false;
|
||||
}
|
||||
|
||||
if(paint_size_ != size)
|
||||
{
|
||||
bool vs = (visible_state::invisible != visible_state_);
|
||||
native_interface::caret_destroy(wd_->root);
|
||||
native_interface::caret_create(wd_->root, size);
|
||||
real_visible_state_ = false;
|
||||
if(visible_)
|
||||
_m_visible(true);
|
||||
//real_visible_state_ = false; //deprecated
|
||||
//if(visible_)
|
||||
// _m_visible(true);
|
||||
|
||||
visible_state_ = visible_state::invisible;
|
||||
if (vs)
|
||||
visible(true);
|
||||
|
||||
|
||||
paint_size_ = size;
|
||||
}
|
||||
@@ -281,6 +313,11 @@ namespace nana
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_window::displayed() const
|
||||
{
|
||||
return (visible && visible_parents());
|
||||
}
|
||||
|
||||
bool basic_window::belong_to_lazy() const
|
||||
{
|
||||
for (auto wd = this; wd; wd = wd->parent)
|
||||
@@ -291,6 +328,26 @@ namespace nana
|
||||
return false;
|
||||
}
|
||||
|
||||
const basic_window* get_child_caret(const basic_window* wd, bool this_is_a_child)
|
||||
{
|
||||
if (this_is_a_child && wd->together.caret)
|
||||
return wd;
|
||||
|
||||
for (auto child : wd->children)
|
||||
{
|
||||
auto caret_wd = get_child_caret(child, true);
|
||||
if (caret_wd)
|
||||
return caret_wd;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const basic_window * basic_window::child_caret() const
|
||||
{
|
||||
return get_child_caret(this, false);
|
||||
}
|
||||
|
||||
bool basic_window::is_draw_through() const
|
||||
{
|
||||
if (::nana::category::flags::root == this->other.category)
|
||||
|
||||
@@ -93,6 +93,18 @@ namespace nana
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
if (emit(event_code::expose, wd, arg, false, get_thread_context()))
|
||||
{
|
||||
const core_window_t * caret_wd = (wd->together.caret ? wd : wd->child_caret());
|
||||
if (caret_wd)
|
||||
{
|
||||
if (exposed)
|
||||
{
|
||||
if (wd->root_widget->other.attribute.root->focus == caret_wd)
|
||||
caret_wd->together.caret->visible(true);
|
||||
}
|
||||
else
|
||||
caret_wd->together.caret->visible(false);
|
||||
}
|
||||
|
||||
if (!exposed)
|
||||
{
|
||||
if (category::flags::root != wd->other.category)
|
||||
@@ -118,7 +130,7 @@ namespace nana
|
||||
arg.x = x;
|
||||
arg.y = y;
|
||||
if (emit(event_code::move, wd, arg, false, get_thread_context()))
|
||||
wd_manager.update(wd, true, true);
|
||||
wd_manager.update(wd, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,99 +34,99 @@ namespace nana
|
||||
|
||||
void drawer_trigger::resizing(graph_reference, const arg_resizing&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::resizing));
|
||||
}
|
||||
|
||||
void drawer_trigger::resized(graph_reference graph, const arg_resized&)
|
||||
{
|
||||
overrided_ = true;
|
||||
overrided_ |= (1 << static_cast<int>(event_code::resized));
|
||||
this->refresh(graph);
|
||||
detail::bedrock::instance().thread_context_lazy_refresh();
|
||||
}
|
||||
|
||||
void drawer_trigger::move(graph_reference, const arg_move&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::move));
|
||||
}
|
||||
|
||||
void drawer_trigger::click(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::click));
|
||||
}
|
||||
|
||||
void drawer_trigger::dbl_click(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::dbl_click));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_enter));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_move(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_move));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_leave));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_down(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_down));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_up(graph_reference, const arg_mouse&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_up));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_wheel));
|
||||
}
|
||||
|
||||
void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_drop));
|
||||
}
|
||||
|
||||
void drawer_trigger::focus(graph_reference, const arg_focus&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::focus));
|
||||
}
|
||||
|
||||
void drawer_trigger::key_press(graph_reference, const arg_keyboard&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::key_press));
|
||||
}
|
||||
|
||||
void drawer_trigger::key_char(graph_reference, const arg_keyboard&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::key_char));
|
||||
}
|
||||
|
||||
void drawer_trigger::key_release(graph_reference, const arg_keyboard&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::key_release));
|
||||
}
|
||||
|
||||
void drawer_trigger::shortkey(graph_reference, const arg_keyboard&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::shortkey));
|
||||
}
|
||||
|
||||
void drawer_trigger::_m_reset_overrided()
|
||||
{
|
||||
overrided_ = true;
|
||||
overrided_ = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
bool drawer_trigger::_m_overrided() const
|
||||
bool drawer_trigger::_m_overrided(event_code evt_code) const
|
||||
{
|
||||
return overrided_;
|
||||
return 0 != (overrided_ & (1 << static_cast<int>(evt_code)));
|
||||
}
|
||||
|
||||
//end class drawer_trigger
|
||||
@@ -240,12 +240,12 @@ namespace nana
|
||||
_m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey);
|
||||
}
|
||||
|
||||
void drawer::map(window wd, bool forced) //Copy the root buffer to screen
|
||||
void drawer::map(window wd, bool forced, const rectangle* update_area) //Copy the root buffer to screen
|
||||
{
|
||||
if(wd)
|
||||
{
|
||||
bedrock_type::core_window_t* iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
|
||||
bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus;
|
||||
auto iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
|
||||
auto caret_wd = iwd->root_widget->other.attribute.root->focus;
|
||||
|
||||
bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible()));
|
||||
|
||||
@@ -262,12 +262,7 @@ namespace nana
|
||||
#endif
|
||||
}
|
||||
|
||||
if (false == edge_nimbus_renderer_t::instance().render(iwd, forced))
|
||||
{
|
||||
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);
|
||||
}
|
||||
edge_nimbus_renderer_t::instance().render(iwd, forced, update_area);
|
||||
|
||||
if(owns_caret)
|
||||
{
|
||||
@@ -302,9 +297,10 @@ namespace nana
|
||||
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;
|
||||
*i = method_state::pending;
|
||||
|
||||
realizer_ = &realizer;
|
||||
realizer._m_reset_overrided();
|
||||
realizer.attached(wd, graphics);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace detail
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void bedrock::map_thread_root_buffer(core_window_t*, bool forced)
|
||||
void bedrock::map_thread_root_buffer(core_window_t*, bool forced, const rectangle*)
|
||||
{
|
||||
//GUI in X11 is thread-independent, so no implementation.
|
||||
}
|
||||
@@ -921,11 +921,10 @@ namespace detail
|
||||
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<Window>(native_window), drawer_impl->context,
|
||||
xevent.xexpose.x, xevent.xexpose.y,
|
||||
xevent.xexpose.width, xevent.xexpose.height,
|
||||
xevent.xexpose.x, xevent.xexpose.y);
|
||||
//Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
|
||||
::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height);
|
||||
if (!update_area.empty())
|
||||
msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
@@ -1011,13 +1010,11 @@ namespace detail
|
||||
{
|
||||
arg_keyboard argkey;
|
||||
brock.get_key_state(argkey);
|
||||
auto tstop_wd = brock.wd_manager.tabstop(msgwnd, argkey.shift);
|
||||
auto tstop_wd = brock.wd_manager.tabstop(msgwnd, !argkey.shift);
|
||||
if (tstop_wd)
|
||||
{
|
||||
brock.wd_manager.set_focus(tstop_wd, false);
|
||||
brock.wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
brock.wd_manager.do_lazy_refresh(tstop_wd, true);
|
||||
root_runtime->condition.tabstop_focus_changed = true;
|
||||
}
|
||||
}
|
||||
else if(keyboard::alt == keychar)
|
||||
@@ -1066,6 +1063,7 @@ namespace detail
|
||||
break;
|
||||
}
|
||||
case XLookupChars:
|
||||
if (msgwnd->flags.enabled)
|
||||
{
|
||||
const ::nana::char_t* charbuf;
|
||||
#if defined(NANA_UNICODE)
|
||||
@@ -1082,6 +1080,10 @@ namespace detail
|
||||
arg.ignore = false;
|
||||
arg.key = charbuf[i];
|
||||
|
||||
// When tab is pressed, only tab-eating mode is allowed
|
||||
if ((keyboard::tab == arg.key) && !(msgwnd->flags.tab & tab_type::eating))
|
||||
continue;
|
||||
|
||||
if(context.is_alt_pressed)
|
||||
{
|
||||
arg.ctrl = arg.shift = false;
|
||||
@@ -1130,7 +1132,9 @@ namespace detail
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||
}
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
|
||||
if (context.platform.keychar < keyboard::os_arrow_left || keyboard::os_arrow_down < wParam)
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -328,9 +328,14 @@ namespace detail
|
||||
return bedrock_object;
|
||||
}
|
||||
|
||||
void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced)
|
||||
void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced, const rectangle* update_area)
|
||||
{
|
||||
::PostMessage(reinterpret_cast<HWND>(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast<WPARAM>(wd), static_cast<LPARAM>(forced ? TRUE : FALSE));
|
||||
auto stru = reinterpret_cast<detail::messages::map_thread*>(::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread)));
|
||||
if (stru)
|
||||
{
|
||||
if (FALSE == ::PostMessage(reinterpret_cast<HWND>(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast<WPARAM>(wd), reinterpret_cast<LPARAM>(stru)))
|
||||
::HeapFree(::GetProcessHeap(), 0, stru);
|
||||
}
|
||||
}
|
||||
|
||||
void interior_helper_for_menu(MSG& msg, native_window_type menu_window)
|
||||
@@ -348,7 +353,7 @@ namespace detail
|
||||
void bedrock::pump_event(window modal_window, bool is_modal)
|
||||
{
|
||||
const unsigned tid = ::GetCurrentThreadId();
|
||||
thread_context * context = this->open_thread_context(tid);
|
||||
auto context = this->open_thread_context(tid);
|
||||
if(0 == context->window_count)
|
||||
{
|
||||
//test if there is not a window
|
||||
@@ -581,8 +586,12 @@ namespace detail
|
||||
}
|
||||
return true;
|
||||
case nana::detail::messages::map_thread_root_buffer:
|
||||
bedrock.wd_manager.map(reinterpret_cast<bedrock::core_window_t*>(wParam), (TRUE == lParam));
|
||||
::UpdateWindow(wd);
|
||||
{
|
||||
auto stru = reinterpret_cast<detail::messages::map_thread*>(lParam);
|
||||
bedrock.wd_manager.map(reinterpret_cast<bedrock::core_window_t*>(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area));
|
||||
::UpdateWindow(wd);
|
||||
::HeapFree(::GetProcessHeap(), 0, stru);
|
||||
}
|
||||
return true;
|
||||
case nana::detail::messages::remote_thread_move_window:
|
||||
{
|
||||
@@ -1282,13 +1291,11 @@ namespace detail
|
||||
::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<HDC>(msgwnd->root_graph->handle()->context),
|
||||
ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
|
||||
}
|
||||
//Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
|
||||
::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
|
||||
if (!update_area.empty())
|
||||
msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
|
||||
|
||||
::EndPaint(root_window, &ps);
|
||||
}
|
||||
break;
|
||||
@@ -1372,7 +1379,7 @@ namespace detail
|
||||
|
||||
if(msgwnd)
|
||||
{
|
||||
if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab
|
||||
if((wParam == 9) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab
|
||||
{
|
||||
bool is_forward = (::GetKeyState(VK_SHIFT) >= 0);
|
||||
|
||||
@@ -1382,7 +1389,6 @@ namespace detail
|
||||
brock.wd_manager.set_focus(tstop_wd, false);
|
||||
brock.wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
brock.wd_manager.do_lazy_refresh(tstop_wd, true);
|
||||
root_runtime->condition.tabstop_focus_changed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1411,9 +1417,10 @@ namespace detail
|
||||
break;
|
||||
case WM_CHAR:
|
||||
msgwnd = brock.focus();
|
||||
if(false == root_runtime->condition.tabstop_focus_changed)
|
||||
if (msgwnd && msgwnd->flags.enabled)
|
||||
{
|
||||
if(msgwnd && msgwnd->flags.enabled)
|
||||
// When tab is pressed, only tab-eating mode is allowed
|
||||
if ((9 != wParam) || (msgwnd->flags.tab & tab_type::eating))
|
||||
{
|
||||
arg_keyboard arg;
|
||||
arg.evt_code = event_code::key_char;
|
||||
@@ -1429,8 +1436,6 @@ namespace detail
|
||||
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
|
||||
@@ -1450,7 +1455,10 @@ namespace detail
|
||||
else
|
||||
brock.set_keyboard_shortkey(false);
|
||||
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
//Do delay restore if key is not arrow_left/right/up/down, otherwise
|
||||
//A menubar will be restored if the item is empty(not have a menu item)
|
||||
if (wParam < 37 || 40 < wParam)
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace nana
|
||||
//class window_layout
|
||||
void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed)
|
||||
{
|
||||
if (wd->flags.refreshing)
|
||||
if (wd->flags.refreshing || wd->drawer.graphics.empty())
|
||||
return;
|
||||
|
||||
if (nullptr == wd->effect.bground)
|
||||
@@ -61,7 +61,6 @@ namespace nana
|
||||
if (wd->parent)
|
||||
{
|
||||
std::vector<wd_rectangle> blocks;
|
||||
blocks.reserve(10);
|
||||
if (read_overlaps(wd, vr, blocks))
|
||||
{
|
||||
nana::point p_src;
|
||||
@@ -101,7 +100,7 @@ namespace nana
|
||||
// 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;
|
||||
if (! wd->displayed()) return false;
|
||||
|
||||
visual = rectangle{ wd->pos_root, wd->dimension };
|
||||
|
||||
@@ -356,7 +355,7 @@ namespace nana
|
||||
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() ||
|
||||
if (wd == sigwd || !wd->displayed() ||
|
||||
(false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd)))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -357,21 +357,26 @@ namespace detail
|
||||
//@brief: Delete the window handle
|
||||
void window_manager::destroy(core_window_t* wd)
|
||||
{
|
||||
core_window_t* parent = nullptr;
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
if (impl_->wd_register.available(wd) == false) return;
|
||||
|
||||
rectangle update_area(wd->pos_owner, wd->dimension);
|
||||
|
||||
auto parent = wd->parent;
|
||||
if (parent)
|
||||
utl::erase(parent->children, wd);
|
||||
|
||||
_m_destroy(wd);
|
||||
|
||||
while (parent && (parent->other.category == ::nana::category::flags::lite_widget))
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> 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_area.x += parent->pos_owner.x;
|
||||
update_area.y += parent->pos_owner.y;
|
||||
parent = parent->parent;
|
||||
}
|
||||
update(parent, false, false);
|
||||
|
||||
update(parent, false, false, &update_area);
|
||||
}
|
||||
|
||||
//destroy_handle
|
||||
@@ -408,35 +413,34 @@ namespace detail
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
if (impl_->wd_register.available(wd))
|
||||
if (!impl_->wd_register.available(wd))
|
||||
return false;
|
||||
|
||||
if(visible != wd->visible)
|
||||
{
|
||||
if(visible != wd->visible)
|
||||
native_window_type nv = nullptr;
|
||||
switch(wd->other.category)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
|
||||
if(visible && wd->effect.bground)
|
||||
window_layer::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::flags::root != wd->other.category)
|
||||
bedrock::instance().event_expose(wd, visible);
|
||||
|
||||
if(nv)
|
||||
native_interface::show_window(nv, visible, wd->flags.take_active);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
window_manager::core_window_t* window_manager::find_window(native_window_type root, int x, int y)
|
||||
@@ -474,9 +478,6 @@ namespace detail
|
||||
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<window>(wd);
|
||||
@@ -503,7 +504,7 @@ namespace detail
|
||||
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)
|
||||
if(category::flags::root != wd->other.category)
|
||||
{
|
||||
//Move child widgets
|
||||
if(r.x != wd->pos_owner.x || r.y != wd->pos_owner.y)
|
||||
@@ -514,9 +515,6 @@ namespace detail
|
||||
_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<window>(wd);
|
||||
arg.x = r.x;
|
||||
@@ -625,7 +623,7 @@ namespace detail
|
||||
if(wd->effect.bground && wd->parent)
|
||||
{
|
||||
wd->other.glass_buffer.make(sz);
|
||||
wndlayout_type::make_bground(wd);
|
||||
window_layer::make_bground(wd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,7 +655,7 @@ namespace detail
|
||||
}
|
||||
|
||||
//Copy the root buffer that wnd specified into DeviceContext
|
||||
void window_manager::map(core_window_t* wd, bool forced)
|
||||
void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area)
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
@@ -665,12 +663,12 @@ namespace detail
|
||||
{
|
||||
//Copy the root buffer that wd specified into DeviceContext
|
||||
#if defined(NANA_LINUX)
|
||||
wd->drawer.map(reinterpret_cast<window>(wd), forced);
|
||||
wd->drawer.map(reinterpret_cast<window>(wd), forced, update_area);
|
||||
#elif defined(NANA_WINDOWS)
|
||||
if(nana::system::this_thread_id() == wd->thread_id)
|
||||
wd->drawer.map(reinterpret_cast<window>(wd), forced);
|
||||
wd->drawer.map(reinterpret_cast<window>(wd), forced, update_area);
|
||||
else
|
||||
bedrock::instance().map_thread_root_buffer(wd, forced);
|
||||
bedrock::instance().map_thread_root_buffer(wd, forced, update_area);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -679,25 +677,25 @@ namespace detail
|
||||
//@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 forced)
|
||||
bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area)
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
if (impl_->wd_register.available(wd) == false) return false;
|
||||
|
||||
if (wd->visible && wd->visible_parents())
|
||||
if (wd->displayed())
|
||||
{
|
||||
if(forced || (false == wd->belong_to_lazy()))
|
||||
{
|
||||
if (!wd->flags.refreshing)
|
||||
{
|
||||
wndlayout_type::paint(wd, redraw, false);
|
||||
this->map(wd, forced);
|
||||
window_layer::paint(wd, redraw, false);
|
||||
this->map(wd, forced, update_area);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(redraw)
|
||||
wndlayout_type::paint(wd, true, false);
|
||||
else if (redraw)
|
||||
window_layer::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;
|
||||
@@ -711,8 +709,8 @@ namespace detail
|
||||
std::lock_guard<decltype(mutex_)> 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);
|
||||
if (impl_->wd_register.available(wd) && wd->displayed())
|
||||
window_layer::paint(wd, true, true);
|
||||
}
|
||||
|
||||
//do_lazy_refresh
|
||||
@@ -733,18 +731,19 @@ namespace detail
|
||||
{
|
||||
if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen)
|
||||
{
|
||||
wndlayout_type::paint(wd, false, false);
|
||||
window_layer::paint(wd, false, false);
|
||||
this->map(wd, force_copy_to_screen);
|
||||
}
|
||||
else if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
|
||||
{
|
||||
//Update the nimbus effect
|
||||
using nimbus_renderer = detail::edge_nimbus_renderer<core_window_t>;
|
||||
nimbus_renderer::instance().render(wd, force_copy_to_screen);
|
||||
//using nimbus_renderer = detail::edge_nimbus_renderer<core_window_t>; //deprecated
|
||||
//nimbus_renderer::instance().render(wd, true);
|
||||
this->map(wd, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
wndlayout_type::paint(wd, true, false); //only refreshing if it has an invisible parent
|
||||
window_layer::paint(wd, true, false); //only refreshing if it has an invisible parent
|
||||
}
|
||||
wd->other.upd_state = core_window_t::update_state::none;
|
||||
return true;
|
||||
@@ -764,7 +763,7 @@ namespace detail
|
||||
|
||||
result.make(wd->drawer.graphics.size());
|
||||
result.bitblt(0, 0, wd->drawer.graphics);
|
||||
wndlayout_type::paste_children_to_graphics(wd, result);
|
||||
window_layer::paste_children_to_graphics(wd, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -773,7 +772,7 @@ namespace detail
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
return (impl_->wd_register.available(wd) ?
|
||||
wndlayout_type::read_visual_rectangle(wd, r) :
|
||||
window_layer::read_visual_rectangle(wd, r) :
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -1002,6 +1001,39 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// preconditions of get_tabstop: tabstop is not empty and at least one window is visible
|
||||
window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward)
|
||||
{
|
||||
auto & tabs = wd->root_widget->other.attribute.root->tabstop;
|
||||
|
||||
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;
|
||||
window_manager::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 are required when moving backward.
|
||||
{
|
||||
auto i = std::find(tabs.cbegin(), tabs.cend(), wd);
|
||||
if (i != tabs.cend())
|
||||
return (tabs.cbegin() == i ? tabs.back() : *(i - 1));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t*
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
@@ -1013,21 +1045,30 @@ namespace detail
|
||||
if (tabs.empty())
|
||||
return nullptr;
|
||||
|
||||
if ((detail::tab_type::none == wd->flags.tab) || !(detail::tab_type::tabstop & wd->flags.tab))
|
||||
return (forward ? tabs.front() : tabs.back());
|
||||
|
||||
auto i = std::find(tabs.cbegin(), tabs.cend(), wd);
|
||||
if (tabs.cend() == i)
|
||||
return (forward ? tabs.front() : tabs.back());
|
||||
|
||||
if (forward)
|
||||
bool precondition = false;
|
||||
for (auto & tab_wd : tabs)
|
||||
{
|
||||
++i;
|
||||
core_window_t* ts = (i != tabs.cend() ? (*i) : tabs.front());
|
||||
return (ts != wd ? ts : nullptr);
|
||||
if (tab_wd->displayed())
|
||||
{
|
||||
precondition = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (tabs.cbegin() == i ? tabs.back() : *(i - 1));
|
||||
|
||||
if (precondition)
|
||||
{
|
||||
auto new_stop = get_tabstop(wd, forward);
|
||||
|
||||
while (new_stop && (wd != new_stop))
|
||||
{
|
||||
if (new_stop->flags.enabled && new_stop->displayed())
|
||||
return new_stop;
|
||||
|
||||
new_stop = get_tabstop(new_stop, forward);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void window_manager::remove_trash_handle(unsigned tid)
|
||||
@@ -1040,7 +1081,7 @@ namespace detail
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
if (impl_->wd_register.available(wd))
|
||||
return wndlayout_type::enable_effects_bground(wd, enabled);
|
||||
return window_layer::enable_effects_bground(wd, enabled);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1224,18 +1265,9 @@ namespace detail
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
//remove the window from edge nimbus effect when it is destroying
|
||||
using edge_nimbus = detail::edge_nimbus_renderer<core_window_t>;
|
||||
edge_nimbus::instance().erase(wd);
|
||||
}
|
||||
else if (pa_root_attr != root_attr)
|
||||
{
|
||||
@@ -1347,7 +1379,7 @@ namespace detail
|
||||
|
||||
|
||||
_m_disengage(wd, nullptr);
|
||||
wndlayout_type::enable_effects_bground(wd, false);
|
||||
window_layer::enable_effects_bground(wd, false);
|
||||
|
||||
wd->drawer.detached();
|
||||
wd->widget_notifier->destroy();
|
||||
@@ -1371,7 +1403,12 @@ namespace detail
|
||||
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)
|
||||
if (category::flags::frame != wd->other.category)
|
||||
{
|
||||
if (wd->together.caret && wd->together.caret->visible())
|
||||
wd->together.caret->update();
|
||||
}
|
||||
else
|
||||
native_interface::move_window(wd->other.attribute.frame->container, wd->pos_root.x, wd->pos_root.y);
|
||||
|
||||
for (auto child : wd->children)
|
||||
|
||||
@@ -722,7 +722,7 @@ namespace API
|
||||
if(restrict::window_manager.available(iwd) && (iwd->flags.enabled != enabled))
|
||||
{
|
||||
iwd->flags.enabled = enabled;
|
||||
restrict::window_manager.update(iwd, true, false);
|
||||
restrict::window_manager.update(iwd, true, true);
|
||||
if(category::flags::root == iwd->other.category)
|
||||
restrict::interface_type::enable_window(iwd->root, enabled);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace nana{ namespace drawerbase
|
||||
|
||||
void trigger::key_char(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if(arg.key == static_cast<char_t>(keyboard::enter))
|
||||
if (static_cast<char_t>(keyboard::enter) == arg.key || static_cast<char_t>(keyboard::space) == arg.key)
|
||||
emit_click();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <nana/gui/widgets/skeletons/text_editor.hpp>
|
||||
#include <nana/gui/widgets/skeletons/textbase_export_interface.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
arg_combox::arg_combox(combox& wdg): widget(wdg)
|
||||
|
||||
@@ -402,18 +402,20 @@ namespace nana
|
||||
return{};
|
||||
}
|
||||
|
||||
void create(nana::string&& text, unsigned pixels)
|
||||
size_type create(nana::string&& text, unsigned pixels)
|
||||
{
|
||||
cont_.emplace_back(std::move(text), pixels, static_cast<size_type>(cont_.size()));
|
||||
return cont_.back().index;
|
||||
}
|
||||
|
||||
void item_width(size_type pos, unsigned width)
|
||||
{
|
||||
for(auto & m : cont_)
|
||||
{
|
||||
if(m.index == pos)
|
||||
{
|
||||
m.pixels = width;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned item_width(size_type pos) const
|
||||
@@ -1606,31 +1608,7 @@ namespace nana
|
||||
}
|
||||
|
||||
/// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_
|
||||
bool categ_selected(size_type cat, bool sel)
|
||||
{
|
||||
bool changed = false;
|
||||
auto & items = _m_at(cat)->items;
|
||||
|
||||
index_pair pos(cat, 0);
|
||||
for(auto & m : items)
|
||||
{
|
||||
if(m.flags.selected != sel)
|
||||
{
|
||||
m.flags.selected = sel;
|
||||
|
||||
arg_listbox arg{ item_proxy(ess_, pos), sel };
|
||||
wd_ptr()->events().selected.emit(arg);
|
||||
changed = true;
|
||||
|
||||
if (sel) // not check for single_selection_
|
||||
last_selected_abs = pos;
|
||||
else if (last_selected_abs == pos)
|
||||
last_selected_abs.set_both(npos);
|
||||
}
|
||||
++pos.item;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
void categ_selected(size_type cat, bool sel);
|
||||
|
||||
void reverse_categ_selected(size_type categ)
|
||||
{
|
||||
@@ -1658,9 +1636,22 @@ namespace nana
|
||||
/// absolute position of the last displayed item
|
||||
index_pair last_displ() const
|
||||
{
|
||||
return absolute ( last_displ() );
|
||||
return absolute ( last() );
|
||||
}
|
||||
|
||||
/// can be used as the absolute position of the first absolute item, or as the display pos of the first displayed item
|
||||
index_pair first() const
|
||||
{
|
||||
index_pair fst{0,npos};
|
||||
good_item(fst,fst);
|
||||
return fst;
|
||||
}
|
||||
/// absolute position of the first displayed item
|
||||
index_pair first_displ() const
|
||||
{
|
||||
return absolute ( first() );
|
||||
}
|
||||
|
||||
bool good(size_type cat) const
|
||||
{
|
||||
return (cat < list_.size());
|
||||
@@ -1670,32 +1661,32 @@ namespace nana
|
||||
{
|
||||
return ((pos.cat < list_.size()) && (pos.item < size_item(pos.cat)));
|
||||
}
|
||||
|
||||
/// if good return the same item (in arg item), or just the next cat and true, but If fail return false
|
||||
bool good_item(index_pair pos, index_pair& item) const
|
||||
{
|
||||
if (!good(pos.cat))
|
||||
return false;
|
||||
return false; // cat out of range
|
||||
|
||||
if (pos.is_category())
|
||||
{
|
||||
item = pos;
|
||||
if (0 == pos.cat)
|
||||
item.item = 0;
|
||||
|
||||
return true;
|
||||
item = pos; // return the cat self
|
||||
if (0 == pos.cat) // but for cat 0 return first item
|
||||
item.item = 0; // let check this is good
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
auto i = _m_at(pos.cat);
|
||||
auto i = _m_at(pos.cat); // pos is not a cat and i point to it cat
|
||||
if (pos.item < i->items.size())
|
||||
{
|
||||
item = pos;
|
||||
item = pos; // good item, return it
|
||||
return true;
|
||||
}
|
||||
|
||||
if (++i == list_.end())
|
||||
if (++i == list_.end()) // item out of range and no more cat
|
||||
return false;
|
||||
|
||||
item.cat = pos.cat + 1;
|
||||
item.cat = pos.cat + 1; // select the next cat
|
||||
item.item = npos;
|
||||
return true;
|
||||
}
|
||||
@@ -1703,7 +1694,7 @@ namespace nana
|
||||
///Translate relative position (position in display) into absolute position (original data order)
|
||||
size_type absolute(const index_pair& display_pos) const
|
||||
{
|
||||
if(sorted_index_ == npos)
|
||||
if(sorted_index_ == npos || display_pos.item == npos)
|
||||
return display_pos.item ;
|
||||
|
||||
auto & catobj = *_m_at(display_pos.cat);
|
||||
@@ -2202,7 +2193,7 @@ namespace nana
|
||||
}
|
||||
else
|
||||
{
|
||||
new_where.second = (y - header_visible_px() + 1) / item_size;
|
||||
new_where.second = ((y + 1) - header_visible_px()) / item_size; // y>1 !
|
||||
new_where.first = parts::lister;
|
||||
if(checkable)
|
||||
{
|
||||
@@ -2324,6 +2315,27 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
unsigned auto_width(size_type pos, unsigned max = 3000) /// \todo introduce parametr max_header_width
|
||||
{
|
||||
unsigned max_w{ 0 };
|
||||
for (const auto &cat : lister.cat_container())
|
||||
for (const auto &it : cat.items)
|
||||
{
|
||||
if (pos >= it.cells.size()) continue;
|
||||
// precalcule text geometry
|
||||
unsigned ts = static_cast<unsigned> (graph->text_extent_size(it.cells[pos].text).width);
|
||||
if (max_w < ts)
|
||||
max_w = ts;
|
||||
}
|
||||
if (!max_w) return 0;
|
||||
|
||||
unsigned ext_w = scheme_ptr->ext_w;
|
||||
if (pos == 0 && checkable) // only before the first column (display_order=0 ?)
|
||||
ext_w += 18;
|
||||
header.item_width(pos, max_w + ext_w + 1 < max ? max_w + ext_w + 1 : max);
|
||||
return max_w;
|
||||
}
|
||||
|
||||
inline_pane * open_inline(pat::abstract_factory<inline_notifier_interface>* factory, inline_indicator* indicator)
|
||||
{
|
||||
std::unique_ptr<inline_pane> pane_ptr;
|
||||
@@ -2494,7 +2506,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
nana::string es_lister::to_string(const export_options& exp_opt) const
|
||||
nana::string es_lister::to_string(const export_options& exp_opt) const
|
||||
{
|
||||
nana::string list_str;
|
||||
bool first{true};
|
||||
@@ -2515,6 +2527,17 @@ namespace nana
|
||||
return list_str ;
|
||||
}
|
||||
|
||||
void es_lister::categ_selected(size_type cat, bool sel)
|
||||
{
|
||||
cat_proxy cpx{ess_,cat};
|
||||
for (item_proxy &it : cpx )
|
||||
{
|
||||
if (it.selected() != sel)
|
||||
it.select(sel);
|
||||
}
|
||||
|
||||
last_selected_abs = last_selected_dpl = index_pair {cat, npos};
|
||||
}
|
||||
|
||||
class drawer_header_impl
|
||||
{
|
||||
@@ -3450,6 +3473,14 @@ namespace nana
|
||||
|
||||
void trigger::dbl_click(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
if (essence_->pointer_where.first == essence_t::parts::header)
|
||||
if (cursor::size_we == essence_->lister.wd_ptr()->cursor())
|
||||
{
|
||||
if (essence(). auto_width(drawer_header_->item_spliter() )) // ? in order
|
||||
essence().update();
|
||||
return;
|
||||
}
|
||||
|
||||
if (essence_->pointer_where.first != essence_t::parts::lister)
|
||||
return;
|
||||
|
||||
@@ -3518,21 +3549,35 @@ namespace nana
|
||||
if (! scrl.make_page_scroll(!up))
|
||||
return;
|
||||
essence_->lister.select_for_all(false);
|
||||
if (up)
|
||||
item_proxy {essence_, essence_->scroll_y_abs()}.select(true);
|
||||
else
|
||||
{
|
||||
index_pair idx{essence_->scroll_y_dpl()};
|
||||
|
||||
index_pair idx{essence_->scroll_y_dpl()};
|
||||
if (!up)
|
||||
essence_->lister.forward(idx, scrl.range()-1, idx);
|
||||
item_proxy::from_display(essence_,idx).select(true);
|
||||
}
|
||||
|
||||
if (idx.is_item())
|
||||
item_proxy::from_display(essence_, idx).select(true);
|
||||
else
|
||||
if(!essence_->lister.single_selection())
|
||||
essence_->lister.categ_selected(idx.cat, true);
|
||||
|
||||
essence_->trace_last_selected_item ();
|
||||
|
||||
break;
|
||||
}
|
||||
case keyboard::os_home:
|
||||
{
|
||||
essence_->lister.select_for_all(false);
|
||||
item_proxy::from_display(essence_, {0,0}).select(true);
|
||||
|
||||
index_pair frst{essence_->lister.first()};
|
||||
if (frst.is_item())
|
||||
item_proxy::from_display(essence_, frst).select(true);
|
||||
else
|
||||
if(!essence_->lister.single_selection())
|
||||
essence_->lister.categ_selected(frst.cat, true);
|
||||
|
||||
essence_->trace_last_selected_item ();
|
||||
break;
|
||||
}
|
||||
case keyboard::os_end:
|
||||
essence_->lister.select_for_all(false);
|
||||
item_proxy::from_display(essence_, essence_->lister.last()).select(true);
|
||||
@@ -3584,7 +3629,7 @@ namespace nana
|
||||
{
|
||||
auto i = ess_->lister.cat_container().begin();
|
||||
std::advance(i, pos.cat);
|
||||
cat_ = &(*i);
|
||||
cat_ = &(*i); // what is pos is a cat?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3617,6 +3662,7 @@ namespace nana
|
||||
m.flags.checked = ck;
|
||||
arg_listbox arg{*this, ck};
|
||||
ess_->lister.wd_ptr()->events().checked.emit(arg);
|
||||
ess_->update();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -3629,7 +3675,7 @@ namespace nana
|
||||
/// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected
|
||||
item_proxy & item_proxy::select(bool s)
|
||||
{
|
||||
auto & m = cat_->items.at(pos_.item); // a ref to the real item
|
||||
auto & m = cat_->items.at(pos_.item); // a ref to the real item // what is pos is a cat?
|
||||
if(m.flags.selected == s) return *this; // ignore if no change
|
||||
m.flags.selected = s; // actually change selection
|
||||
|
||||
@@ -3646,6 +3692,7 @@ namespace nana
|
||||
|
||||
ess_->update();
|
||||
|
||||
ess_->update();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -3865,6 +3912,24 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
cat_proxy & cat_proxy::select(bool sel)
|
||||
{
|
||||
for (item_proxy &it : *this )
|
||||
it.select(sel);
|
||||
|
||||
ess_->lister.last_selected_abs =
|
||||
ess_->lister.last_selected_dpl = index_pair {this->pos_, npos};
|
||||
|
||||
return *this;
|
||||
}
|
||||
bool cat_proxy::selected() const
|
||||
{
|
||||
for (item_proxy &it : *this )
|
||||
if (!it.selected())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto cat_proxy::columns() const -> size_type
|
||||
{
|
||||
return ess_->header.cont().size();
|
||||
@@ -3907,6 +3972,11 @@ namespace nana
|
||||
//Behavior of a container
|
||||
item_proxy cat_proxy::begin() const
|
||||
{
|
||||
auto i = ess_->lister.cat_container().begin();
|
||||
std::advance(i, pos_);
|
||||
if (i->items.empty())
|
||||
return end();
|
||||
|
||||
return item_proxy(ess_, index_pair(pos_, 0));
|
||||
}
|
||||
|
||||
@@ -4121,11 +4191,12 @@ namespace nana
|
||||
_m_ess().set_auto_draw(ad);
|
||||
}
|
||||
|
||||
void listbox::append_header(nana::string text, unsigned width)
|
||||
listbox::size_type listbox::append_header(nana::string text, unsigned width)
|
||||
{
|
||||
auto & ess = _m_ess();
|
||||
ess.header.create(std::move(text), width);
|
||||
listbox::size_type index = ess.header.create(std::move(text), width);
|
||||
ess.update();
|
||||
return index;
|
||||
}
|
||||
|
||||
listbox& listbox::header_width(size_type pos, unsigned pixels)
|
||||
@@ -4135,6 +4206,13 @@ namespace nana
|
||||
ess.update();
|
||||
return *this;
|
||||
}
|
||||
unsigned listbox::auto_width(size_type pos, unsigned max)
|
||||
{
|
||||
auto & ess = _m_ess();
|
||||
unsigned max_w = ess.auto_width(pos, max);
|
||||
ess.update();
|
||||
return max_w;
|
||||
}
|
||||
|
||||
unsigned listbox::header_width(size_type pos) const
|
||||
{
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace nana
|
||||
{
|
||||
if(at.item_state == state::active)
|
||||
{
|
||||
graph.rectangle(r, false, {0xa8, 0xd8, 0xeb});
|
||||
graph.rectangle(r, false, static_cast<color_rgb>(0xa8d8eb));
|
||||
nana::point points[4] = {
|
||||
nana::point(r.x, r.y),
|
||||
nana::point(r.x + r.width - 1, r.y),
|
||||
@@ -144,9 +144,9 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
void item_image(graph_reference graph, const nana::point& pos, const paint::image& img)
|
||||
void item_image(graph_reference graph, const nana::point& pos, unsigned image_px, const paint::image& img)
|
||||
{
|
||||
img.paste(graph, pos.x, pos.y);
|
||||
img.stretch(rectangle{ img.size() }, graph, rectangle{ pos, ::nana::size(image_px, image_px) });
|
||||
}
|
||||
|
||||
void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at)
|
||||
@@ -200,35 +200,35 @@ namespace nana
|
||||
|
||||
void checked(std::size_t index, bool check)
|
||||
{
|
||||
if(root_.items.size() > index)
|
||||
if (root_.items.size() <= index)
|
||||
return;
|
||||
|
||||
item_type & m = root_.items[index];
|
||||
if(check && (checks::option == m.style))
|
||||
{
|
||||
item_type & m = root_.items[index];
|
||||
if(check && (checks::option == m.style))
|
||||
if(index)
|
||||
{
|
||||
if(index)
|
||||
std::size_t i = index;
|
||||
do
|
||||
{
|
||||
std::size_t i = index;
|
||||
do
|
||||
{
|
||||
item_type& el = root_.items[--i];
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}while(i);
|
||||
}
|
||||
|
||||
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
|
||||
{
|
||||
item_type & el = root_.items[i];
|
||||
item_type& el = root_.items[--i];
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}
|
||||
}while(i);
|
||||
}
|
||||
|
||||
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
|
||||
{
|
||||
item_type & el = root_.items[i];
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}
|
||||
m.flags.checked = check;
|
||||
}
|
||||
m.flags.checked = check;
|
||||
}
|
||||
|
||||
menu_type& data()
|
||||
@@ -304,7 +304,7 @@ namespace nana
|
||||
: public drawer_trigger
|
||||
{
|
||||
public:
|
||||
typedef menu_item_type::item_proxy item_proxy;
|
||||
using item_proxy = menu_item_type::item_proxy;
|
||||
|
||||
renderer_interface * renderer;
|
||||
|
||||
@@ -330,12 +330,12 @@ namespace nana
|
||||
detail_.monitor_pos = API::cursor_position();
|
||||
}
|
||||
|
||||
void mouse_move(graph_reference, const arg_mouse& arg)
|
||||
void mouse_move(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
state_.nullify_mouse = false;
|
||||
if(track_mouse(arg.pos.x, arg.pos.y))
|
||||
if(track_mouse(arg.pos))
|
||||
{
|
||||
draw();
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
@@ -350,9 +350,70 @@ namespace nana
|
||||
state_.nullify_mouse = false;
|
||||
}
|
||||
|
||||
void refresh(graph_reference)
|
||||
void refresh(graph_reference graph)
|
||||
{
|
||||
draw();
|
||||
if (nullptr == menu_) return;
|
||||
|
||||
_m_adjust_window_size();
|
||||
|
||||
renderer->background(graph, *widget_);
|
||||
|
||||
const unsigned item_h_px = _m_item_height();
|
||||
const unsigned image_px = item_h_px - 2;
|
||||
nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
|
||||
|
||||
unsigned strpixels = item_r.width - 60;
|
||||
|
||||
int text_top_off = (item_h_px - graph.text_extent_size(STR("jh({[")).height) / 2;
|
||||
|
||||
std::size_t pos = 0;
|
||||
for (auto & m : menu_->items)
|
||||
{
|
||||
if (m.flags.splitter)
|
||||
{
|
||||
graph_->set_color(colors::gray_border);
|
||||
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y });
|
||||
item_r.y += 2;
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
|
||||
//Draw item background
|
||||
renderer->item(*graph_, item_r, attr);
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
nana::char_t hotkey;
|
||||
nana::string::size_type hotkey_pos;
|
||||
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
|
||||
|
||||
if (m.image.empty() == false)
|
||||
renderer->item_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, m.image);
|
||||
|
||||
renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
|
||||
|
||||
if (hotkey)
|
||||
{
|
||||
m.hotkey = hotkey;
|
||||
if (m.flags.enabled)
|
||||
{
|
||||
unsigned off_w = (hotkey_pos ? graph.text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
|
||||
nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1);
|
||||
int x = item_r.x + 40 + off_w;
|
||||
int y = item_r.y + text_top_off + hotkey_size.height;
|
||||
|
||||
graph_->set_color(colors::black);
|
||||
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
|
||||
}
|
||||
}
|
||||
|
||||
if (m.sub_menu)
|
||||
renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
|
||||
|
||||
item_r.y += item_r.height + 1;
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t active() const
|
||||
@@ -411,21 +472,21 @@ namespace nana
|
||||
state_.active = pos;
|
||||
state_.sub_window = false;
|
||||
|
||||
draw();
|
||||
refresh(*graph_);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool track_mouse(int x, int y)
|
||||
bool track_mouse(const ::nana::point& pos)
|
||||
{
|
||||
if(state_.nullify_mouse == false)
|
||||
if (!state_.nullify_mouse)
|
||||
{
|
||||
std::size_t index = _m_get_index_by_pos(x, y);
|
||||
if(index != state_.active)
|
||||
std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
|
||||
if (index != state_.active)
|
||||
{
|
||||
if((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
|
||||
if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
|
||||
return false;
|
||||
|
||||
state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index;
|
||||
@@ -433,6 +494,7 @@ namespace nana
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -451,29 +513,35 @@ namespace nana
|
||||
state_.sub_window = subw;
|
||||
}
|
||||
|
||||
menu_type* retrive_sub_menu(nana::point& pos, std::size_t interval) const
|
||||
menu_type* get_sub(nana::point& pos, unsigned long& tmstamp) const
|
||||
{
|
||||
if(state_.active != npos && (nana::system::timestamp() - state_.active_timestamp >= interval))
|
||||
if (npos == state_.active)
|
||||
return nullptr;
|
||||
|
||||
auto sub = menu_->items.at(state_.active).sub_menu;
|
||||
if (sub)
|
||||
{
|
||||
pos.x = graph_->width() - 2;
|
||||
pos.x = static_cast<int>(graph_->width()) - 2;
|
||||
pos.y = 2;
|
||||
|
||||
std::size_t index = 0;
|
||||
for(auto & m : menu_->items)
|
||||
auto index = state_.active;
|
||||
for (auto & m : menu_->items)
|
||||
{
|
||||
if(false == m.flags.splitter)
|
||||
if (m.flags.splitter)
|
||||
{
|
||||
if(index == state_.active)
|
||||
break;
|
||||
|
||||
pos.y += _m_item_height() + 1;
|
||||
}
|
||||
else
|
||||
pos.y += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
++index;
|
||||
if (0 == index)
|
||||
break;
|
||||
|
||||
pos.y += _m_item_height() + 1;
|
||||
--index;
|
||||
}
|
||||
return (menu_->items.at(state_.active).sub_menu);
|
||||
|
||||
tmstamp = state_.active_timestamp;
|
||||
return sub;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -498,8 +566,7 @@ namespace nana
|
||||
state_.active = index;
|
||||
state_.active_timestamp = nana::system::timestamp();
|
||||
|
||||
draw();
|
||||
API::update_window(*widget_);
|
||||
API::refresh_window(*widget_);
|
||||
return 2;
|
||||
}
|
||||
else if(m.flags.enabled)
|
||||
@@ -514,71 +581,6 @@ namespace nana
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void draw() const
|
||||
{
|
||||
if(nullptr == menu_) return;
|
||||
|
||||
_m_adjust_window_size();
|
||||
|
||||
renderer->background(*graph_, *widget_);
|
||||
|
||||
const unsigned item_h_px = _m_item_height();
|
||||
nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
|
||||
|
||||
unsigned strpixels = item_r.width - 60;
|
||||
|
||||
int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
|
||||
|
||||
std::size_t pos = 0;
|
||||
for(auto & m : menu_->items)
|
||||
{
|
||||
if(m.flags.splitter)
|
||||
{
|
||||
graph_->set_color(colors::gray_border);
|
||||
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
|
||||
item_r.y += 2;
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
|
||||
//Draw item background
|
||||
renderer->item(*graph_, item_r, attr);
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
nana::char_t hotkey;
|
||||
nana::string::size_type hotkey_pos;
|
||||
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
|
||||
|
||||
if(m.image.empty() == false)
|
||||
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
|
||||
|
||||
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
|
||||
|
||||
if(hotkey)
|
||||
{
|
||||
m.hotkey = hotkey;
|
||||
if(m.flags.enabled)
|
||||
{
|
||||
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
|
||||
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
|
||||
int x = item_r.x + 40 + off_w;
|
||||
int y = item_r.y + text_top_off + hotkey_size.height;
|
||||
|
||||
graph_->set_color(colors::black);
|
||||
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
|
||||
}
|
||||
}
|
||||
|
||||
if(m.sub_menu)
|
||||
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
|
||||
|
||||
item_r.y += item_r.height + 1;
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
private:
|
||||
static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m)
|
||||
{
|
||||
@@ -683,10 +685,10 @@ namespace nana
|
||||
|
||||
struct state
|
||||
{
|
||||
std::size_t active;
|
||||
unsigned long active_timestamp;
|
||||
unsigned long sub_window: 1;
|
||||
unsigned long nullify_mouse: 1;
|
||||
std::size_t active;
|
||||
unsigned active_timestamp;
|
||||
bool sub_window: 1;
|
||||
bool nullify_mouse: 1;
|
||||
}state_;
|
||||
|
||||
struct widget_detail
|
||||
@@ -699,15 +701,18 @@ namespace nana
|
||||
class menu_window
|
||||
: public widget_object<category::root_tag, menu_drawer>
|
||||
{
|
||||
typedef menu_drawer drawer_type;
|
||||
typedef widget_object<category::root_tag, menu_drawer> base_type;
|
||||
using drawer_type = menu_drawer;
|
||||
using base_type = widget_object<category::root_tag, menu_drawer>;
|
||||
public:
|
||||
typedef menu_builder::item_type item_type;
|
||||
using item_type = menu_builder::item_type;
|
||||
|
||||
menu_window(window wd, const point& pos, renderer_interface * rdptr)
|
||||
|
||||
menu_window(window wd, bool is_wd_parent_menu, const point& pos, renderer_interface * rdptr)
|
||||
//add a is_wd_parent_menu to determine whether the menu wants the focus.
|
||||
//if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed
|
||||
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
|
||||
want_focus_(nullptr == wd || (API::focus_window() != wd)),
|
||||
event_focus_(nullptr)
|
||||
want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::focus_window() != wd)) },
|
||||
event_focus_{ nullptr }
|
||||
{
|
||||
caption(STR("nana menu window"));
|
||||
get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); });
|
||||
@@ -718,7 +723,19 @@ namespace nana
|
||||
submenu_.child = submenu_.parent = nullptr;
|
||||
submenu_.object = nullptr;
|
||||
|
||||
_m_make_mouse_event();
|
||||
state_.mouse_pos = API::cursor_position();
|
||||
events().mouse_move.connect_unignorable([this]{
|
||||
nana::point pos = API::cursor_position();
|
||||
if (pos != state_.mouse_pos)
|
||||
{
|
||||
menu_window * root = this;
|
||||
while (root->submenu_.parent)
|
||||
root = root->submenu_.parent;
|
||||
root->state_.auto_popup_submenu = true;
|
||||
|
||||
state_.mouse_pos = pos;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void popup(menu_type& menu, bool owner_menubar)
|
||||
@@ -745,13 +762,19 @@ namespace nana
|
||||
_m_key_down(arg);
|
||||
});
|
||||
|
||||
events().mouse_up.connect_unignorable([this]{
|
||||
pick();
|
||||
events().mouse_down.connect_unignorable([this](const arg_mouse& arg)
|
||||
{
|
||||
this->_m_open_sub(0); //Try to open submenu immediately
|
||||
});
|
||||
|
||||
events().mouse_up.connect_unignorable([this](const arg_mouse& arg){
|
||||
if (arg.left_button)
|
||||
pick();
|
||||
});
|
||||
|
||||
timer_.interval(100);
|
||||
timer_.elapse([this]{
|
||||
this->_m_check_repeatly();
|
||||
this->_m_open_sub(500); //Try to open submenu
|
||||
});
|
||||
timer_.start();
|
||||
|
||||
@@ -797,29 +820,27 @@ namespace nana
|
||||
|
||||
bool submenu(bool enter)
|
||||
{
|
||||
menu_window * object = this;
|
||||
while (object->submenu_.child)
|
||||
object = object->submenu_.child;
|
||||
menu_window * menu_wd = this;
|
||||
while (menu_wd->submenu_.child)
|
||||
menu_wd = menu_wd->submenu_.child;
|
||||
|
||||
state_.auto_popup_submenu = false;
|
||||
|
||||
if (enter)
|
||||
if (!enter)
|
||||
{
|
||||
if (object->submenu_.parent)
|
||||
if (menu_wd->submenu_.parent)
|
||||
{
|
||||
auto & sub = object->submenu_.parent->submenu_;
|
||||
auto & sub = menu_wd->submenu_.parent->submenu_;
|
||||
sub.child = nullptr;
|
||||
sub.object = nullptr;
|
||||
|
||||
object->close();
|
||||
menu_wd->close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nana::point pos;
|
||||
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
|
||||
return object->_m_show_submenu(sbm, pos, true);
|
||||
return menu_wd->_m_manipulate_sub(0, true);
|
||||
}
|
||||
|
||||
int send_shortkey(nana::char_t key)
|
||||
@@ -965,63 +986,51 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
void _m_make_mouse_event()
|
||||
bool _m_manipulate_sub(unsigned long delay_ms, bool forced)
|
||||
{
|
||||
state_.mouse_pos = API::cursor_position();
|
||||
events().mouse_move.connect_unignorable([this]{
|
||||
_m_mouse_event();
|
||||
});
|
||||
}
|
||||
auto & drawer = get_drawer_trigger();
|
||||
::nana::point pos;
|
||||
unsigned long tmstamp;
|
||||
|
||||
void _m_mouse_event()
|
||||
{
|
||||
nana::point pos = API::cursor_position();
|
||||
if(pos != state_.mouse_pos)
|
||||
auto menu_ptr = drawer.get_sub(pos, tmstamp);
|
||||
|
||||
if (menu_ptr == submenu_.object)
|
||||
return false;
|
||||
|
||||
if (menu_ptr && (::nana::system::timestamp() - tmstamp < delay_ms))
|
||||
return false;
|
||||
|
||||
if (submenu_.object && (menu_ptr != submenu_.object))
|
||||
{
|
||||
menu_window * root = this;
|
||||
while(root->submenu_.parent)
|
||||
root = root->submenu_.parent;
|
||||
root->state_.auto_popup_submenu = true;
|
||||
|
||||
state_.mouse_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
bool _m_show_submenu(menu_type* sbm, nana::point pos, bool forced)
|
||||
{
|
||||
auto & mdtrigger = get_drawer_trigger();
|
||||
if(submenu_.object && (sbm != submenu_.object))
|
||||
{
|
||||
mdtrigger.set_sub_window(false);
|
||||
drawer.set_sub_window(false);
|
||||
submenu_.child->close();
|
||||
submenu_.child = nullptr;
|
||||
submenu_.object = nullptr;
|
||||
}
|
||||
|
||||
if(sbm)
|
||||
if (menu_ptr)
|
||||
{
|
||||
menu_window * root = this;
|
||||
while(root->submenu_.parent)
|
||||
while (root->submenu_.parent)
|
||||
root = root->submenu_.parent;
|
||||
|
||||
if((submenu_.object == nullptr) && sbm && (forced || root->state_.auto_popup_submenu))
|
||||
if ((submenu_.object == nullptr) && menu_ptr && (forced || root->state_.auto_popup_submenu))
|
||||
{
|
||||
sbm->item_pixels = mdtrigger.data()->item_pixels;
|
||||
sbm->gaps = mdtrigger.data()->gaps;
|
||||
pos.x += sbm->gaps.x;
|
||||
pos.y += sbm->gaps.y;
|
||||
menu_ptr->item_pixels = drawer.data()->item_pixels;
|
||||
menu_ptr->gaps = drawer.data()->gaps;
|
||||
pos += menu_ptr->gaps;
|
||||
|
||||
menu_window & mwnd = form_loader<menu_window, false>()(handle(), pos, mdtrigger.renderer);
|
||||
menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.renderer);
|
||||
mwnd.state_.self_submenu = true;
|
||||
submenu_.child = & mwnd;
|
||||
submenu_.child = &mwnd;
|
||||
submenu_.child->submenu_.parent = this;
|
||||
submenu_.object = sbm;
|
||||
submenu_.object = menu_ptr;
|
||||
|
||||
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
|
||||
|
||||
mwnd.popup(*sbm, state_.owner_menubar);
|
||||
mdtrigger.set_sub_window(true);
|
||||
if(forced)
|
||||
mwnd.popup(*menu_ptr, state_.owner_menubar);
|
||||
drawer.set_sub_window(true);
|
||||
if (forced)
|
||||
mwnd.goto_next(true);
|
||||
|
||||
return true;
|
||||
@@ -1030,17 +1039,16 @@ namespace nana
|
||||
return false;
|
||||
}
|
||||
|
||||
void _m_check_repeatly()
|
||||
void _m_open_sub(unsigned delay_ms) //check_repeatly
|
||||
{
|
||||
if(state_.auto_popup_submenu)
|
||||
{
|
||||
nana::point pos = API::cursor_position();
|
||||
auto pos = API::cursor_position();
|
||||
|
||||
drawer_type& drawer = get_drawer_trigger();
|
||||
API::calc_window_point(handle(), pos);
|
||||
drawer.track_mouse(pos.x, pos.y);
|
||||
menu_type* sbm = drawer.retrive_sub_menu(pos, 500);
|
||||
_m_show_submenu(sbm, pos, false);
|
||||
get_drawer_trigger().track_mouse(pos);
|
||||
|
||||
_m_manipulate_sub(delay_ms, false);
|
||||
}
|
||||
}
|
||||
private:
|
||||
@@ -1293,7 +1301,7 @@ namespace nana
|
||||
{
|
||||
close();
|
||||
|
||||
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
|
||||
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, point(x, y), &(*impl_->mbuilder.renderer())));
|
||||
impl_->uiobj->events().destroy.connect_unignorable([this]{
|
||||
impl_->uiobj = nullptr;
|
||||
if (impl_->destroy_answer)
|
||||
|
||||
@@ -89,6 +89,15 @@ namespace nana
|
||||
{
|
||||
return unknown_;
|
||||
}
|
||||
bool trigger::stoped() const
|
||||
{
|
||||
return stop_;
|
||||
}
|
||||
bool trigger::stop(bool s)
|
||||
{
|
||||
std::swap(s,stop_);
|
||||
return s;
|
||||
}
|
||||
|
||||
void trigger::refresh(graph_reference)
|
||||
{
|
||||
@@ -197,5 +206,13 @@ namespace nana
|
||||
{
|
||||
return get_drawer_trigger().unknown();
|
||||
}
|
||||
bool progress::stop(bool s)
|
||||
{
|
||||
return get_drawer_trigger().stop(s);
|
||||
}
|
||||
bool progress::stoped() const
|
||||
{
|
||||
return get_drawer_trigger().stoped();
|
||||
}
|
||||
//end class progress
|
||||
}//end namespace nana
|
||||
|
||||
@@ -1482,6 +1482,8 @@ namespace nana{ namespace widgets
|
||||
|
||||
behavior_->pre_calc_lines(width_pixels());
|
||||
_m_scrollbar();
|
||||
|
||||
move_caret(points_.caret);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/toolbar.hpp>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <nana/gui/tooltip.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn)
|
||||
@@ -25,13 +25,6 @@ namespace nana
|
||||
{
|
||||
namespace toolbar
|
||||
{
|
||||
struct listitem
|
||||
{
|
||||
nana::string text;
|
||||
nana::paint::image image;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
struct item_type
|
||||
{
|
||||
enum kind{ button, container};
|
||||
@@ -43,28 +36,23 @@ namespace nana
|
||||
unsigned pixels{0};
|
||||
nana::size textsize;
|
||||
bool enable{true};
|
||||
window other{nullptr};
|
||||
|
||||
kind type;
|
||||
std::function<void(size_type, size_type)> answer;
|
||||
std::vector<listitem> children;
|
||||
|
||||
item_type(const nana::string& text, const nana::paint::image& img, kind type)
|
||||
:text(text), image(img), type(type)
|
||||
{}
|
||||
};
|
||||
|
||||
class container
|
||||
{
|
||||
container(const container&) = delete;
|
||||
container& operator=(const container&) = delete;
|
||||
public:
|
||||
typedef std::vector<item_type*>::size_type size_type;
|
||||
typedef std::vector<item_type*>::iterator iterator;
|
||||
typedef std::vector<item_type*>::const_iterator const_iterator;
|
||||
|
||||
container() = default;
|
||||
~container()
|
||||
|
||||
class item_container
|
||||
{
|
||||
public:
|
||||
using container_type = std::vector<item_type*>;
|
||||
using size_type = container_type::size_type;
|
||||
|
||||
~item_container()
|
||||
{
|
||||
for(auto ptr : cont_)
|
||||
delete ptr;
|
||||
@@ -98,7 +86,7 @@ namespace nana
|
||||
cont_.push_back(nullptr);
|
||||
}
|
||||
|
||||
void push_back()
|
||||
void separate()
|
||||
{
|
||||
cont_.push_back(nullptr);
|
||||
}
|
||||
@@ -108,35 +96,17 @@ namespace nana
|
||||
return cont_.size();
|
||||
}
|
||||
|
||||
item_type* at(size_type n)
|
||||
container_type& container()
|
||||
{
|
||||
if(n < cont_.size())
|
||||
return cont_[n];
|
||||
|
||||
throw std::out_of_range("toolbar: bad index!");
|
||||
return cont_;
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
item_type * at(size_type pos)
|
||||
{
|
||||
return cont_.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return cont_.end();
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return cont_.cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return cont_.cend();
|
||||
return cont_.at(pos);
|
||||
}
|
||||
private:
|
||||
std::vector<item_type*> cont_;
|
||||
container_type cont_;
|
||||
};
|
||||
|
||||
class item_renderer
|
||||
@@ -152,38 +122,36 @@ namespace nana
|
||||
void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state)
|
||||
{
|
||||
//draw background
|
||||
if(state != state_t::normal)
|
||||
graph.rectangle({ x, y, width, height }, false, { 0x33, 0x99, 0xFF });
|
||||
switch(state)
|
||||
if (state != state_t::normal)
|
||||
{
|
||||
case state_t::highlighted:
|
||||
graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0xC0, 0xDD, 0xFC }, true);
|
||||
break;
|
||||
case state_t::selected:
|
||||
graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0x99, 0xCC, 0xFF }, true);
|
||||
default: break;
|
||||
nana::rectangle background_r(x, y, width, height);
|
||||
graph.rectangle(background_r, false, static_cast<color_rgb>(0x3399FF));
|
||||
|
||||
if (state_t::highlighted == state || state_t::selected == state)
|
||||
graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast<color_rgb>(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true);
|
||||
}
|
||||
|
||||
if(item.image.empty() == false)
|
||||
if(!item.image.empty())
|
||||
{
|
||||
nana::size size = item.image.size();
|
||||
if(size.width > scale) size.width = scale;
|
||||
if(size.height > scale) size.height = scale;
|
||||
auto imgsize = item.image.size();
|
||||
|
||||
if (imgsize.width > scale) imgsize.width = scale;
|
||||
if (imgsize.height > scale) imgsize.height = scale;
|
||||
|
||||
nana::point pos(x, y);
|
||||
pos.x += static_cast<int>(scale + extra_size - size.width) / 2;
|
||||
pos.y += static_cast<int>(height - size.height) / 2;
|
||||
pos.x += static_cast<int>(scale + extra_size - imgsize.width) / 2;
|
||||
pos.y += static_cast<int>(height - imgsize.height) / 2;
|
||||
|
||||
item.image.paste(::nana::rectangle{ size }, graph, pos);
|
||||
item.image.paste(::nana::rectangle{ imgsize }, graph, pos);
|
||||
if(item.enable == false)
|
||||
{
|
||||
nana::paint::graphics gh(size);
|
||||
gh.bitblt(::nana::rectangle{ size }, graph, pos);
|
||||
nana::paint::graphics gh(imgsize);
|
||||
gh.bitblt(::nana::rectangle{ imgsize }, graph, pos);
|
||||
gh.rgb_to_wb();
|
||||
gh.paste(graph, pos.x, pos.y);
|
||||
}
|
||||
else if(state == state_t::normal)
|
||||
graph.blend(nana::rectangle(pos, size), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25);
|
||||
graph.blend(nana::rectangle(pos, imgsize), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25);
|
||||
|
||||
x += scale;
|
||||
width -= scale;
|
||||
@@ -204,13 +172,15 @@ namespace nana
|
||||
|
||||
struct drawer::drawer_impl_type
|
||||
{
|
||||
event_handle event_size{nullptr};
|
||||
event_handle event_size{ nullptr };
|
||||
paint::graphics* graph_ptr{ nullptr };
|
||||
|
||||
unsigned scale{16};
|
||||
bool textout{false};
|
||||
size_type which{npos};
|
||||
item_renderer::state_t state{item_renderer::state_t::normal};
|
||||
|
||||
container cont;
|
||||
item_container items;
|
||||
::nana::tooltip tooltip;
|
||||
};
|
||||
|
||||
@@ -225,116 +195,118 @@ namespace nana
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void drawer::append(const nana::string& text, const nana::paint::image& img)
|
||||
item_container& drawer::items() const
|
||||
{
|
||||
impl_->cont.push_back(text, img);
|
||||
}
|
||||
|
||||
void drawer::append()
|
||||
{
|
||||
impl_->cont.push_back();
|
||||
}
|
||||
|
||||
bool drawer::enable(drawer::size_type n) const
|
||||
{
|
||||
if(impl_->cont.size() > n)
|
||||
{
|
||||
auto item = impl_->cont.at(n);
|
||||
return (item && item->enable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool drawer::enable(size_type n, bool eb)
|
||||
{
|
||||
if(impl_->cont.size() > n)
|
||||
{
|
||||
item_type * item = impl_->cont.at(n);
|
||||
if(item && (item->enable != eb))
|
||||
{
|
||||
item->enable = eb;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return impl_->items;
|
||||
}
|
||||
|
||||
void drawer::scale(unsigned s)
|
||||
{
|
||||
impl_->scale = s;
|
||||
|
||||
for(auto m : impl_->cont)
|
||||
_m_fill_pixels(m, true);
|
||||
for(auto m : impl_->items.container())
|
||||
_m_calc_pixels(m, true);
|
||||
}
|
||||
|
||||
void drawer::refresh(graph_reference)
|
||||
void drawer::refresh(graph_reference graph)
|
||||
{
|
||||
_m_draw();
|
||||
int x = 2, y = 2;
|
||||
|
||||
auto bgcolor = API::bgcolor(widget_->handle());
|
||||
graph.set_text_color(bgcolor);
|
||||
graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.95), true);
|
||||
|
||||
item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor);
|
||||
size_type index = 0;
|
||||
|
||||
for (auto item : impl_->items.container())
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
_m_calc_pixels(item, false);
|
||||
ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal));
|
||||
x += item->pixels;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += 2;
|
||||
graph.line({ x, y + 2 }, { x, y + static_cast<int>(impl_->scale + ir.extra_size) - 4 }, static_cast<color_rgb>(0x808080));
|
||||
x += 4;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::attached(widget_reference widget, graph_reference graph)
|
||||
{
|
||||
graph_ = &graph;
|
||||
impl_->graph_ptr = &graph;
|
||||
|
||||
widget_ = static_cast< ::nana::toolbar*>(&widget);
|
||||
widget.caption(STR("Nana Toolbar"));
|
||||
impl_->event_size = widget.events().resized.connect_unignorable(std::bind(&drawer::_m_owner_sized, this, std::placeholders::_1));
|
||||
widget.caption(L"Nana Toolbar");
|
||||
|
||||
impl_->event_size = API::events(widget.parent()).resized.connect_unignorable([this](const arg_resized& arg)
|
||||
{
|
||||
auto wd = widget_->handle();
|
||||
API::window_size(wd, nana::size(arg.width, widget_->size().height));
|
||||
API::update_window(wd);
|
||||
});
|
||||
}
|
||||
|
||||
void drawer::detached()
|
||||
{
|
||||
API::umake_event(impl_->event_size);
|
||||
impl_->event_size = nullptr;
|
||||
impl_->graph_ptr = nullptr;
|
||||
}
|
||||
|
||||
void drawer::mouse_move(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
if(arg.left_button == false)
|
||||
if (arg.left_button)
|
||||
return;
|
||||
|
||||
size_type which = _m_which(arg.pos, true);
|
||||
if(impl_->which != which)
|
||||
{
|
||||
size_type which = _m_which(arg.pos.x, arg.pos.y, true);
|
||||
if(impl_->which != which)
|
||||
auto & container = impl_->items.container();
|
||||
if (impl_->which != npos && container.at(impl_->which)->enable)
|
||||
{
|
||||
if (impl_->which != npos && impl_->cont.at(impl_->which)->enable)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, impl_->which };
|
||||
widget_->events().leave.emit(arg);
|
||||
}
|
||||
|
||||
impl_->which = which;
|
||||
if(which == npos || impl_->cont.at(which)->enable)
|
||||
{
|
||||
impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
|
||||
if (impl_->state == item_renderer::state_t::highlighted)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
widget_->events().enter.emit(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if(which != npos)
|
||||
impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(impl_->cont.begin() + which))->text, 0);
|
||||
else
|
||||
impl_->tooltip.close();
|
||||
::nana::arg_toolbar arg{ *widget_, impl_->which };
|
||||
widget_->events().leave.emit(arg);
|
||||
}
|
||||
|
||||
impl_->which = which;
|
||||
if (which == npos || container.at(which)->enable)
|
||||
{
|
||||
impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
|
||||
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
|
||||
if (impl_->state == item_renderer::state_t::highlighted)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
widget_->events().enter.emit(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if(which != npos)
|
||||
impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(container.begin() + which))->text, 0);
|
||||
else
|
||||
impl_->tooltip.close();
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::mouse_leave(graph_reference, const arg_mouse&)
|
||||
void drawer::mouse_leave(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
if(impl_->which != npos)
|
||||
{
|
||||
size_type which = impl_->which;
|
||||
|
||||
impl_->which = npos;
|
||||
_m_draw();
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
|
||||
if (which != npos && impl_->cont.at(which)->enable)
|
||||
if (which != npos && impl_->items.at(which)->enable)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
widget_->events().leave.emit(arg);
|
||||
@@ -343,22 +315,22 @@ namespace nana
|
||||
impl_->tooltip.close();
|
||||
}
|
||||
|
||||
void drawer::mouse_down(graph_reference, const arg_mouse&)
|
||||
void drawer::mouse_down(graph_reference graph, const arg_mouse&)
|
||||
{
|
||||
impl_->tooltip.close();
|
||||
if(impl_->which != npos && (impl_->cont.at(impl_->which)->enable))
|
||||
if(impl_->which != npos && (impl_->items.at(impl_->which)->enable))
|
||||
{
|
||||
impl_->state = item_renderer::state_t::selected;
|
||||
_m_draw();
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::mouse_up(graph_reference, const arg_mouse& arg)
|
||||
void drawer::mouse_up(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
if(impl_->which != npos)
|
||||
{
|
||||
size_type which = _m_which(arg.pos.x, arg.pos.y, false);
|
||||
size_type which = _m_which(arg.pos, false);
|
||||
if(impl_->which == which)
|
||||
{
|
||||
::nana::arg_toolbar arg{ *widget_, which };
|
||||
@@ -372,89 +344,47 @@ namespace nana
|
||||
impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted);
|
||||
}
|
||||
|
||||
_m_draw();
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
drawer::size_type drawer::_m_which(int x, int y, bool want_if_disabled) const
|
||||
drawer::size_type drawer::_m_which(point pos, bool want_if_disabled) const
|
||||
{
|
||||
if(x < 2 || y < 2 || y >= static_cast<int>(impl_->scale + item_renderer::extra_size + 2)) return npos;
|
||||
if (pos.x < 2 || pos.y < 2 || pos.y >= static_cast<int>(impl_->scale + item_renderer::extra_size + 2)) return npos;
|
||||
|
||||
x -= 2;
|
||||
pos.x -= 2;
|
||||
|
||||
size_type pos = 0;
|
||||
for(auto m: impl_->cont)
|
||||
std::size_t index = 0;
|
||||
for(auto m: impl_->items.container())
|
||||
{
|
||||
bool compart = (nullptr == m);
|
||||
auto px = static_cast<const int>(m ? m->pixels : 3);
|
||||
|
||||
if(x < static_cast<int>(compart ? 3 : m->pixels))
|
||||
return ((compart || (m->enable == false && want_if_disabled == false)) ? npos : pos);
|
||||
if(pos.x < px)
|
||||
return (((!m) || (!m->enable && !want_if_disabled)) ? npos : index);
|
||||
|
||||
x -= (compart ? 3 : m->pixels);
|
||||
pos.x -= px;
|
||||
|
||||
++pos;
|
||||
++index;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
void drawer::_m_draw_background(const ::nana::color& clr)
|
||||
void drawer::_m_calc_pixels(item_type* item, bool force)
|
||||
{
|
||||
graph_->gradual_rectangle(::nana::rectangle{ graph_->size() }, clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true);
|
||||
}
|
||||
|
||||
void drawer::_m_draw()
|
||||
{
|
||||
int x = 2, y = 2;
|
||||
|
||||
auto bgcolor = API::bgcolor(widget_->handle());
|
||||
graph_->set_text_color(bgcolor);
|
||||
_m_draw_background(bgcolor);
|
||||
|
||||
item_renderer ir(*graph_, impl_->textout, impl_->scale, bgcolor);
|
||||
size_type index = 0;
|
||||
|
||||
for(auto item : impl_->cont)
|
||||
if (item && (force || (0 == item->pixels)))
|
||||
{
|
||||
if(item)
|
||||
{
|
||||
_m_fill_pixels(item, false);
|
||||
ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal));
|
||||
x += item->pixels;
|
||||
}
|
||||
else
|
||||
{
|
||||
graph_->line({ x + 2, y + 2 }, { x + 2, y + static_cast<int>(impl_->scale + ir.extra_size) - 4 }, { 0x80, 0x80, 0x80 });
|
||||
x += 6;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
if (item->text.size())
|
||||
item->textsize = impl_->graph_ptr->text_extent_size(item->text);
|
||||
|
||||
void drawer::_m_owner_sized(const arg_resized& arg)
|
||||
{
|
||||
auto wd = widget_->handle();
|
||||
API::window_size(wd, nana::size(arg.width, widget_->size().height));
|
||||
_m_draw();
|
||||
API::update_window(wd);
|
||||
}
|
||||
|
||||
void drawer::_m_fill_pixels(item_type* item, bool force)
|
||||
{
|
||||
if(item && (force || (0 == item->pixels)))
|
||||
{
|
||||
if(item->text.size())
|
||||
item->textsize = graph_->text_extent_size(item->text);
|
||||
|
||||
if(item->image.empty() == false)
|
||||
if (item->image.empty() == false)
|
||||
item->pixels = impl_->scale + item_renderer::extra_size;
|
||||
|
||||
if(item->textsize.width && impl_->textout)
|
||||
if (item->textsize.width && impl_->textout)
|
||||
item->pixels += item->textsize.width + 8;
|
||||
}
|
||||
}
|
||||
//};//class drawer
|
||||
|
||||
//class drawer
|
||||
}//end namespace toolbar
|
||||
}//end namespace drawerbase
|
||||
|
||||
@@ -469,33 +399,48 @@ namespace nana
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
void toolbar::append()
|
||||
void toolbar::separate()
|
||||
{
|
||||
get_drawer_trigger().append();
|
||||
get_drawer_trigger().items().separate();
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
|
||||
void toolbar::append(const nana::string& text, const nana::paint::image& img)
|
||||
{
|
||||
get_drawer_trigger().append(text, img);
|
||||
get_drawer_trigger().items().push_back(text, img);
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
|
||||
void toolbar::append(const nana::string& text)
|
||||
{
|
||||
get_drawer_trigger().append(text, nana::paint::image());
|
||||
get_drawer_trigger().items().push_back(text, {});
|
||||
API::refresh_window(this->handle());
|
||||
}
|
||||
|
||||
bool toolbar::enable(size_type n) const
|
||||
bool toolbar::enable(size_type pos) const
|
||||
{
|
||||
return get_drawer_trigger().enable(n);
|
||||
auto & items = get_drawer_trigger().items();
|
||||
|
||||
if (items.size() <= pos)
|
||||
return false;
|
||||
|
||||
auto m = items.at(pos);
|
||||
return (m && m->enable);
|
||||
}
|
||||
|
||||
void toolbar::enable(size_type n, bool eb)
|
||||
void toolbar::enable(size_type pos, bool eb)
|
||||
{
|
||||
if(get_drawer_trigger().enable(n, eb))
|
||||
API::refresh_window(this->handle());
|
||||
auto & items = get_drawer_trigger().items();
|
||||
|
||||
if (items.size() > pos)
|
||||
{
|
||||
auto m = items.at(pos);
|
||||
if (m && (m->enable != eb))
|
||||
{
|
||||
m->enable = eb;
|
||||
API::refresh_window(this->handle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void toolbar::scale(unsigned s)
|
||||
@@ -503,5 +448,5 @@ namespace nana
|
||||
get_drawer_trigger().scale(s);
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
//}; class toolbar
|
||||
//end class toolbar
|
||||
}//end namespace nana
|
||||
|
||||
@@ -156,6 +156,9 @@ namespace detail
|
||||
|
||||
nana::size text_extent_size(drawable_type dw, const nana::char_t * text, std::size_t len)
|
||||
{
|
||||
if (nullptr == dw || nullptr == text || 0 == len)
|
||||
return{};
|
||||
|
||||
nana::size extents = raw_text_extent_size(dw, text, len);
|
||||
|
||||
const nana::char_t* const end = text + len;
|
||||
|
||||
Reference in New Issue
Block a user