nim_duilib/examples/multi_browser/browser/multi_browser_manager.cpp

394 lines
10 KiB
C++
Raw Normal View History

2019-04-19 17:19:57 +08:00
#include "multi_browser_manager.h"
#include "multi_browser_form.h"
#include "browser_box.h"
#include "dragdrop/drag_form.h"
#include "dragdrop/drag_drop.h"
namespace
{
const int kSplitFormXOffset = 20; //自动拆分浏览器窗口后新窗口的x偏移坐标
const int kSplitFormYOffset = 20; //自动拆分浏览器窗口后新窗口的y偏移坐标
const int kDragFormXOffset = -100; //拖拽出新浏览器窗口后的相对鼠标的x偏移坐标
const int kDragFormYOffset = -20; //拖拽出新浏览器窗口后的相对鼠标的y偏移坐标
}
BrowserBox* MultiBrowserManager::CreateBorwserBox(MultiBrowserForm *browser_form, const std::string &id, const std::wstring &url)
{
BrowserBox *browser_box = NULL;
// 如果启用了窗口合并功能,就把新浏览器盒子都集中创建到某一个浏览器窗口里
// 否则每个浏览器盒子都创建一个浏览器窗口
if (enable_merge_)
{
if (!browser_form)
{
browser_form = new MultiBrowserForm;
HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
if (hwnd == NULL)
{
browser_form = NULL;
return NULL;
}
browser_form->CenterWindow();
}
browser_box = browser_form->CreateBox(id, url);
if (NULL == browser_box)
return NULL;
}
else
{
browser_form = new MultiBrowserForm;
HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
if (hwnd == NULL)
return NULL;
browser_box = browser_form->CreateBox(id, url);
if (NULL == browser_box)
return NULL;
browser_form->CenterWindow();
}
box_map_[id] = browser_box;
return browser_box;
}
MultiBrowserManager::MultiBrowserManager()
{
enable_merge_ = true;
use_custom_drag_image_ = true;
}
MultiBrowserManager::~MultiBrowserManager()
{
}
bool MultiBrowserManager::IsBorwserBoxActive(const std::string& id)
{
BrowserBox *browser_box = FindBorwserBox(id);
if (NULL != browser_box)
{
MultiBrowserForm *parent_form = browser_box->GetBrowserForm();
return parent_form->IsActiveBox(browser_box);
}
return false;
}
BrowserBox* MultiBrowserManager::FindBorwserBox( const std::string &id )
{
std::map<std::string, BrowserBox*>::const_iterator i = box_map_.find(id);
if (i == box_map_.end())
return NULL;
else
return i->second;
}
void MultiBrowserManager::RemoveBorwserBox( std::string id, const BrowserBox* box /*=NULL*/)
{
auto it_box = box_map_.find(id);
if (it_box == box_map_.end())
{
assert(0);
}
else
{
if (NULL == box || box == it_box->second)
{
box_map_.erase(it_box);
}
else
{
assert(0);
}
}
if (box_map_.empty())
nim_comp::CefManager::GetInstance()->PostQuitMessage(0);
2019-04-19 17:19:57 +08:00
}
void MultiBrowserManager::SetEnableMerge(bool enable)
{
if (enable_merge_ == enable)
return;
enable_merge_ = enable;
if (enable_merge_)
{
// 如果当前只有一个浏览器窗口或者浏览器盒子,就不需要进行合并操作
if (box_map_.size() <= 1)
return;
// 选择第一个浏览器盒子所属的窗口作为合并窗口
MultiBrowserForm *merge_form = box_map_.begin()->second->GetBrowserForm();
// 遍历所有浏览器盒子,脱离原浏览器窗口,再附加到合并窗口里
for (auto it_box : box_map_)
{
ASSERT(NULL != it_box.second);
MultiBrowserForm *parent_form = it_box.second->GetBrowserForm();
if (merge_form != parent_form)
{
if (parent_form->DetachBox(it_box.second))
{
merge_form->AttachBox(it_box.second);
}
}
}
}
else
{
// 如果当前只有一个浏览器盒子,就不需要进行拆分操作
if (box_map_.size() <= 1)
return;
// 给新拆分的窗口设置坐标
bool first_sort = true;
ui::UiRect rect_old_form;
MultiBrowserForm *sort_form = NULL;
// 遍历所有浏览器盒子,脱离原浏览器窗口,创建新的浏览器窗口并附加浏览器盒子
for (auto it_box : box_map_)
{
ASSERT(NULL != it_box.second);
MultiBrowserForm *parent_form = it_box.second->GetBrowserForm();
if (1 == parent_form->GetBoxCount())
{
sort_form = parent_form;
}
else if (parent_form->DetachBox(it_box.second))
{
MultiBrowserForm *browser_form = new MultiBrowserForm;
HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
if (hwnd == NULL)
{
ASSERT(0);
continue;
}
if (!browser_form->AttachBox(it_box.second))
{
ASSERT(0);
continue;
}
sort_form = browser_form;
}
if (NULL != sort_form)
{
if (first_sort)
{
first_sort = false;
sort_form->CenterWindow();
rect_old_form = sort_form->GetPos(true);
}
else
{
rect_old_form.left += kSplitFormXOffset;
rect_old_form.top += kSplitFormXOffset;
sort_form->SetPos(rect_old_form, true, SWP_NOSIZE, NULL, true);
}
}
}
}
}
bool MultiBrowserManager::IsEnableMerge() const
{
return enable_merge_;
}
void MultiBrowserManager::SetUseCustomDragImage(bool use)
{
use_custom_drag_image_ = use;
}
bool MultiBrowserManager::IsUseCustomDragImage() const
{
return use_custom_drag_image_;
}
bool MultiBrowserManager::IsDragingBorwserBox() const
{
return enable_merge_ && NULL != draging_box_;
}
void MultiBrowserManager::SetDropForm(MultiBrowserForm *browser_form)
{
if (NULL == browser_form)
return;
drop_browser_form_ = browser_form;
}
bool MultiBrowserManager::DoDragBorwserBox(BrowserBox *browser_box, HBITMAP bitmap, POINT pt_offset)
{
if (!enable_merge_)
return false;
SdkDropSource* drop_src = new SdkDropSource;
if (drop_src == NULL)
return false;
SdkDataObject* data_object = CreateDragDataObject(bitmap, pt_offset);
if (data_object == NULL)
return false;
// 无论什么时候都让拖拽时光标显示为箭头
drop_src->SetFeedbackCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
OnBeforeDragBorwserBox(browser_box, bitmap, pt_offset);
// 此函数会阻塞直到拖拽完成
DWORD dwEffect;
HRESULT hr = ::DoDragDrop(data_object, drop_src, DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
OnAfterDragBorwserBox();
// 销毁位图
DeleteObject(bitmap);
drop_src->Release();
data_object->Release();
return true;
}
SdkDataObject* MultiBrowserManager::CreateDragDataObject(HBITMAP bitmap, POINT pt_offset)
{
SdkDataObject* data_object = new SdkDataObject;
if (data_object == NULL)
return NULL;
if (use_custom_drag_image_)
{
FORMATETC fmtetc = { 0 };
fmtetc.dwAspect = DVASPECT_CONTENT;
fmtetc.lindex = -1;
fmtetc.cfFormat = CF_HDROP;
fmtetc.tymed = TYMED_NULL;
STGMEDIUM medium = { 0 };
medium.tymed = TYMED_NULL;
data_object->SetData(&fmtetc, &medium, FALSE);
}
else
{
FORMATETC fmtetc = { 0 };
fmtetc.dwAspect = DVASPECT_CONTENT;
fmtetc.lindex = -1;
fmtetc.cfFormat = CF_BITMAP;
fmtetc.tymed = TYMED_GDI;
STGMEDIUM medium = { 0 };
medium.tymed = TYMED_GDI;
HBITMAP hBitmap = (HBITMAP)OleDuplicateData(bitmap, fmtetc.cfFormat, NULL);
medium.hBitmap = hBitmap;
data_object->SetData(&fmtetc, &medium, FALSE);
BITMAP bitmap_info;
GetObject(hBitmap, sizeof(BITMAP), &bitmap_info);
SIZE bitmap_size = { bitmap_info.bmWidth, bitmap_info.bmHeight };
SdkDragSourceHelper dragSrcHelper;
dragSrcHelper.InitializeFromBitmap(hBitmap, pt_offset, bitmap_size, data_object, RGB(255, 0, 255));
}
return data_object;
}
void MultiBrowserManager::OnBeforeDragBorwserBox(BrowserBox *browser_box, HBITMAP bitmap, POINT pt_offset)
{
// 获取当前被拖拽的浏览器盒子所属的浏览器窗口
draging_box_ = browser_box;
MultiBrowserForm *drag_browser_form = draging_box_->GetBrowserForm();
ASSERT(NULL != drag_browser_form);
// 获取被拖拽浏览器窗口中浏览器盒子的数量
int box_count = drag_browser_form->GetBoxCount();
ASSERT(box_count > 0);
drop_browser_form_ = NULL;
drag_browser_form->OnBeforeDragBoxCallback(nbase::UTF8ToUTF16(draging_box_->GetId()));
if (use_custom_drag_image_)
DragForm::CreateCustomDragImage(bitmap, pt_offset);
}
void MultiBrowserManager::OnAfterDragBorwserBox()
{
if (use_custom_drag_image_)
DragForm::CloseCustomDragImage();
if (NULL == draging_box_)
return;
// 获取当前被拖拽的浏览器盒子所属的浏览器窗口
MultiBrowserForm *drag_browser_form = draging_box_->GetBrowserForm();
ASSERT(NULL != drag_browser_form);
// 获取被拖拽浏览器窗口中浏览器盒子的数量
int box_count = drag_browser_form->GetBoxCount();
ASSERT(box_count > 0);
// 如果被拖拽的浏览器盒子放入到一个浏览器窗口里
if (NULL != drop_browser_form_)
{
if (drag_browser_form == drop_browser_form_)
{
drag_browser_form->OnAfterDragBoxCallback(false);
}
else
{
drag_browser_form->OnAfterDragBoxCallback(true);
if (drag_browser_form->DetachBox(draging_box_))
{
drop_browser_form_->AttachBox(draging_box_);
}
}
// 如果被拖拽的浏览器窗口包含多个浏览器盒子就投递一个WM_LBUTTONUP消息给窗口
// (因为窗口被拖拽时触发了ButtonDown和ButtonMove消息但是最终的ButtonUp消息会被忽略这里补上)
// 如果只有一个浏览器盒子,则浏览器盒子脱离浏览器窗口时,浏览器窗口就会关闭,不需要投递
if (box_count > 1)
drag_browser_form->PostMessage(WM_LBUTTONUP, 0, 0);
}
// 如果没有被拖拽到另一个浏览器窗口里
else
{
// 如果被拖拽的浏览器窗口里只有一个浏览器盒子,则拖拽失败
if (1 == box_count)
{
drag_browser_form->OnAfterDragBoxCallback(false);
}
// 如果有多个浏览器盒子, 就把浏览器盒子脱离原浏览器窗口,附加到新的浏览器窗口,拖拽成功
else
{
drag_browser_form->OnAfterDragBoxCallback(true);
if (drag_browser_form->DetachBox(draging_box_))
{
MultiBrowserForm *browser_form = new MultiBrowserForm;
HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
if (hwnd != NULL)
{
if (browser_form->AttachBox(draging_box_))
{
// 这里设置新浏览器窗口的位置设置到偏移鼠标坐标100,20的位置
POINT pt_mouse;
::GetCursorPos(&pt_mouse);
ui::UiRect rect(pt_mouse.x + kDragFormXOffset, pt_mouse.y + kDragFormYOffset, 0, 0);
browser_form->SetPos(rect, false, SWP_NOSIZE);
}
}
}
}
// 如果没有被拖拽到另一个浏览器窗口里这时不会有浏览器窗口被关闭所以直接投递ButtonUp消息
drag_browser_form->PostMessage(WM_LBUTTONUP, 0, 0);
}
draging_box_ = NULL;
drop_browser_form_ = NULL;
}