190 lines
6.8 KiB
C
190 lines
6.8 KiB
C
|
// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be found
|
||
|
// in the LICENSE file.
|
||
|
|
||
|
#ifndef CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
|
||
|
#define CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
|
||
|
#pragma once
|
||
|
|
||
|
#include "include/views/cef_view.h"
|
||
|
#include "include/views/cef_view_delegate.h"
|
||
|
|
||
|
#include "libcef/browser/thread_util.h"
|
||
|
#include "libcef/browser/views/view_util.h"
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
#include "ui/views/background.h"
|
||
|
#include "ui/views/view.h"
|
||
|
|
||
|
// Helpers for template boiler-plate.
|
||
|
#define CEF_VIEW_VIEW_T \
|
||
|
template <class ViewsViewClass, class CefViewDelegateClass>
|
||
|
#define CEF_VIEW_VIEW_A \
|
||
|
ViewsViewClass, CefViewDelegateClass
|
||
|
#define CEF_VIEW_VIEW_D CefViewView<CEF_VIEW_VIEW_A>
|
||
|
|
||
|
// Base template for implementing views::View-derived classes. The views::View-
|
||
|
// derived type passed to this template must provide a no-argument constructor
|
||
|
// (for example, see LabelButtonEx from basic_label_button_view.h). See comments
|
||
|
// in view_impl.h for a usage overview.
|
||
|
CEF_VIEW_VIEW_T class CefViewView : public ViewsViewClass {
|
||
|
public:
|
||
|
typedef ViewsViewClass ParentClass;
|
||
|
|
||
|
// |cef_delegate| may be nullptr.
|
||
|
explicit CefViewView(CefViewDelegateClass* cef_delegate)
|
||
|
: cef_delegate_(cef_delegate) {
|
||
|
// Use our defaults instead of the Views framework defaults.
|
||
|
ParentClass::set_background(views::Background::CreateSolidBackground(
|
||
|
view_util::kDefaultBackgroundColor));
|
||
|
}
|
||
|
|
||
|
// Returns the CefViewDelegate-derived delegate associated with this view.
|
||
|
// May return nullptr.
|
||
|
CefViewDelegateClass* cef_delegate() const { return cef_delegate_; }
|
||
|
|
||
|
// Returns the CefView associated with this view. May return nullptr during
|
||
|
// CefViewImpl initialization. If callbacks to the CefViewImpl-derived class
|
||
|
// are required define an interface that the CefViewImpl-derived class can
|
||
|
// implement and pass as an unowned instance to this object's constructor (see
|
||
|
// for example CefWindowView).
|
||
|
CefRefPtr<CefView> GetCefView() const {
|
||
|
CefRefPtr<CefView> view = view_util::GetFor(this, false);
|
||
|
DCHECK(view);
|
||
|
return view;
|
||
|
}
|
||
|
|
||
|
// views::View methods:
|
||
|
gfx::Size GetPreferredSize() const override;
|
||
|
gfx::Size GetMinimumSize() const override;
|
||
|
gfx::Size GetMaximumSize() const override;
|
||
|
int GetHeightForWidth(int w) const override;
|
||
|
void Layout() override;
|
||
|
void ViewHierarchyChanged(
|
||
|
const views::View::ViewHierarchyChangedDetails& details) override;
|
||
|
|
||
|
// Return true if this View is expected to have a minimum size (for example,
|
||
|
// a button where the minimum size is based on the label).
|
||
|
virtual bool HasMinimumSize() const { return false; }
|
||
|
|
||
|
private:
|
||
|
void NotifyChildViewChanged(
|
||
|
const views::View::ViewHierarchyChangedDetails& details);
|
||
|
void NotifyParentViewChanged(
|
||
|
const views::View::ViewHierarchyChangedDetails& details);
|
||
|
|
||
|
// Not owned by this object.
|
||
|
CefViewDelegateClass* cef_delegate_;
|
||
|
};
|
||
|
|
||
|
CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetPreferredSize() const {
|
||
|
gfx::Size result;
|
||
|
if (cef_delegate()) {
|
||
|
CefSize cef_size = cef_delegate()->GetPreferredSize(GetCefView());
|
||
|
if (!cef_size.IsEmpty())
|
||
|
result = gfx::Size(cef_size.width, cef_size.height);
|
||
|
}
|
||
|
if (result.IsEmpty())
|
||
|
result = ParentClass::GetPreferredSize();
|
||
|
if (result.IsEmpty()) {
|
||
|
// Some layouts like BoxLayout expect the preferred size to be non-empty.
|
||
|
// The user may have set the size explicitly. Therefore return the current
|
||
|
// size as the preferred size.
|
||
|
result = ParentClass::size();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetMinimumSize() const {
|
||
|
gfx::Size result;
|
||
|
if (cef_delegate()) {
|
||
|
CefSize cef_size = cef_delegate()->GetMinimumSize(GetCefView());
|
||
|
if (!cef_size.IsEmpty())
|
||
|
result = gfx::Size(cef_size.width, cef_size.height);
|
||
|
}
|
||
|
// We don't want to call ParentClass::GetMinimumSize() in all cases because
|
||
|
// the default views::View implementation will call GetPreferredSize(). That
|
||
|
// may result in size() being returned which keeps the View from shrinking.
|
||
|
if (result.IsEmpty() && HasMinimumSize())
|
||
|
result = ParentClass::GetMinimumSize();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetMaximumSize() const {
|
||
|
gfx::Size result;
|
||
|
if (cef_delegate()) {
|
||
|
CefSize cef_size = cef_delegate()->GetMaximumSize(GetCefView());
|
||
|
if (!cef_size.IsEmpty())
|
||
|
result = gfx::Size(cef_size.width, cef_size.height);
|
||
|
}
|
||
|
if (result.IsEmpty())
|
||
|
result = ParentClass::GetMaximumSize();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T int CEF_VIEW_VIEW_D::GetHeightForWidth(int w) const {
|
||
|
int result = 0;
|
||
|
if (cef_delegate())
|
||
|
result = cef_delegate()->GetHeightForWidth(GetCefView(), w);
|
||
|
if (result == 0)
|
||
|
result = ParentClass::GetHeightForWidth(w);
|
||
|
if (result == 0) {
|
||
|
// Some layouts like FillLayout will ignore the preferred size if this view
|
||
|
// has no children. We want to use the preferred size if not otherwise
|
||
|
// specified.
|
||
|
result = GetPreferredSize().height();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::Layout() {
|
||
|
ParentClass::Layout();
|
||
|
|
||
|
// If Layout() did not provide a size then use the preferred size.
|
||
|
if (ParentClass::size().IsEmpty())
|
||
|
ParentClass::SizeToPreferredSize();
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::ViewHierarchyChanged(
|
||
|
const views::View::ViewHierarchyChangedDetails& details) {
|
||
|
NotifyChildViewChanged(details);
|
||
|
NotifyParentViewChanged(details);
|
||
|
ParentClass::ViewHierarchyChanged(details);
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyChildViewChanged(
|
||
|
const views::View::ViewHierarchyChangedDetails& details) {
|
||
|
if (!cef_delegate())
|
||
|
return;
|
||
|
|
||
|
// Only interested with the parent is |this| object and the notification is
|
||
|
// about an immediate child (notifications are also sent for grandchildren).
|
||
|
if (details.parent != this || details.child->parent() != this)
|
||
|
return;
|
||
|
|
||
|
// Only notify for children that have a known CEF root view. For example,
|
||
|
// don't notify when ScrollView adds child scroll bars.
|
||
|
CefRefPtr<CefView> child = view_util::GetFor(details.child, false);
|
||
|
if (child)
|
||
|
cef_delegate()->OnChildViewChanged(GetCefView(), details.is_add, child);
|
||
|
}
|
||
|
|
||
|
CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyParentViewChanged(
|
||
|
const views::View::ViewHierarchyChangedDetails& details) {
|
||
|
if (!cef_delegate())
|
||
|
return;
|
||
|
|
||
|
// Only interested when the child is |this| object and notification is about
|
||
|
// the immediate parent (notifications are sent for all parents).
|
||
|
if (details.child != this || details.parent != ParentClass::parent())
|
||
|
return;
|
||
|
|
||
|
// The immediate parent might be an intermediate view so find the closest
|
||
|
// known CEF root view.
|
||
|
CefRefPtr<CefView> parent = view_util::GetFor(details.parent, true);
|
||
|
DCHECK(parent);
|
||
|
cef_delegate()->OnParentViewChanged(GetCefView(), details.is_add, parent);
|
||
|
}
|
||
|
|
||
|
#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
|