win_caption_button_container.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // Modified from
  5. // chrome/browser/ui/views/frame/glass_browser_caption_button_container.cc
  6. #include "shell/browser/ui/views/win_caption_button_container.h"
  7. #include <memory>
  8. #include <utility>
  9. #include <windows.h>
  10. #include <winuser.h>
  11. #include "shell/browser/native_window_views.h"
  12. #include "shell/browser/ui/views/win_caption_button.h"
  13. #include "shell/browser/ui/views/win_frame_view.h"
  14. #include "ui/base/l10n/l10n_util.h"
  15. #include "ui/compositor/layer.h"
  16. #include "ui/strings/grit/ui_strings.h"
  17. #include "ui/views/accessibility/view_accessibility.h"
  18. #include "ui/views/background.h"
  19. #include "ui/views/layout/flex_layout.h"
  20. #include "ui/views/view_class_properties.h"
  21. namespace electron {
  22. namespace {
  23. std::unique_ptr<WinCaptionButton> CreateCaptionButton(
  24. views::Button::PressedCallback callback,
  25. WinFrameView* frame_view,
  26. ViewID button_type,
  27. int accessible_name_resource_id) {
  28. return std::make_unique<WinCaptionButton>(
  29. std::move(callback), frame_view, button_type,
  30. l10n_util::GetStringUTF16(accessible_name_resource_id));
  31. }
  32. bool HitTestCaptionButton(WinCaptionButton* button, const gfx::Point& point) {
  33. return button && button->GetVisible() &&
  34. button->GetMirroredBounds().Contains(point);
  35. }
  36. } // anonymous namespace
  37. WinCaptionButtonContainer::WinCaptionButtonContainer(WinFrameView* frame_view)
  38. : frame_view_(frame_view),
  39. minimize_button_(AddChildView(CreateCaptionButton(
  40. base::BindRepeating(&NativeWindow::Minimize,
  41. base::Unretained(frame_view_->window())),
  42. frame_view_,
  43. VIEW_ID_MINIMIZE_BUTTON,
  44. IDS_APP_ACCNAME_MINIMIZE))),
  45. maximize_button_(AddChildView(CreateCaptionButton(
  46. base::BindRepeating(&NativeWindow::Maximize,
  47. base::Unretained(frame_view_->window())),
  48. frame_view_,
  49. VIEW_ID_MAXIMIZE_BUTTON,
  50. IDS_APP_ACCNAME_MAXIMIZE))),
  51. restore_button_(AddChildView(CreateCaptionButton(
  52. base::BindRepeating(&NativeWindow::Restore,
  53. base::Unretained(frame_view_->window())),
  54. frame_view_,
  55. VIEW_ID_RESTORE_BUTTON,
  56. IDS_APP_ACCNAME_RESTORE))),
  57. close_button_(AddChildView(CreateCaptionButton(
  58. base::BindRepeating(&NativeWindow::Close,
  59. base::Unretained(frame_view_->window())),
  60. frame_view_,
  61. VIEW_ID_CLOSE_BUTTON,
  62. IDS_APP_ACCNAME_CLOSE))) {
  63. // Layout is horizontal, with buttons placed at the trailing end of the view.
  64. // This allows the container to expand to become a faux titlebar/drag handle.
  65. auto* const layout = SetLayoutManager(std::make_unique<views::FlexLayout>());
  66. layout->SetOrientation(views::LayoutOrientation::kHorizontal)
  67. .SetMainAxisAlignment(views::LayoutAlignment::kEnd)
  68. .SetCrossAxisAlignment(views::LayoutAlignment::kStart)
  69. .SetDefault(
  70. views::kFlexBehaviorKey,
  71. views::FlexSpecification(views::LayoutOrientation::kHorizontal,
  72. views::MinimumFlexSizeRule::kPreferred,
  73. views::MaximumFlexSizeRule::kPreferred,
  74. /* adjust_width_for_height */ false,
  75. views::MinimumFlexSizeRule::kScaleToZero));
  76. UpdateButtonToolTipsForWindowControlsOverlay();
  77. }
  78. WinCaptionButtonContainer::~WinCaptionButtonContainer() {}
  79. int WinCaptionButtonContainer::NonClientHitTest(const gfx::Point& point) const {
  80. DCHECK(HitTestPoint(point))
  81. << "should only be called with a point inside this view's bounds";
  82. if (HitTestCaptionButton(minimize_button_, point)) {
  83. return HTMINBUTTON;
  84. }
  85. if (HitTestCaptionButton(maximize_button_, point)) {
  86. return HTMAXBUTTON;
  87. }
  88. if (HitTestCaptionButton(restore_button_, point)) {
  89. return HTMAXBUTTON;
  90. }
  91. if (HitTestCaptionButton(close_button_, point)) {
  92. return HTCLOSE;
  93. }
  94. return HTCAPTION;
  95. }
  96. void WinCaptionButtonContainer::ResetWindowControls() {
  97. minimize_button_->SetState(views::Button::STATE_NORMAL);
  98. maximize_button_->SetState(views::Button::STATE_NORMAL);
  99. restore_button_->SetState(views::Button::STATE_NORMAL);
  100. close_button_->SetState(views::Button::STATE_NORMAL);
  101. InvalidateLayout();
  102. }
  103. void WinCaptionButtonContainer::AddedToWidget() {
  104. views::Widget* const widget = GetWidget();
  105. DCHECK(!widget_observation_.IsObserving());
  106. widget_observation_.Observe(widget);
  107. UpdateButtons();
  108. UpdateBackground();
  109. }
  110. void WinCaptionButtonContainer::RemovedFromWidget() {
  111. DCHECK(widget_observation_.IsObserving());
  112. widget_observation_.Reset();
  113. }
  114. void WinCaptionButtonContainer::OnWidgetBoundsChanged(
  115. views::Widget* widget,
  116. const gfx::Rect& new_bounds) {
  117. UpdateButtons();
  118. }
  119. void WinCaptionButtonContainer::UpdateBackground() {
  120. const SkColor bg_color = frame_view_->window()->overlay_button_color();
  121. const SkAlpha theme_alpha = SkColorGetA(bg_color);
  122. SetBackground(views::CreateSolidBackground(bg_color));
  123. SetPaintToLayer();
  124. if (theme_alpha < SK_AlphaOPAQUE)
  125. layer()->SetFillsBoundsOpaquely(false);
  126. }
  127. void WinCaptionButtonContainer::UpdateButtons() {
  128. const bool minimizable = frame_view_->window()->IsMinimizable();
  129. minimize_button_->SetEnabled(minimizable);
  130. minimize_button_->SetVisible(minimizable);
  131. const bool is_maximized = frame_view_->window()->IsMaximized();
  132. const bool maximizable = frame_view_->window()->IsMaximizable();
  133. restore_button_->SetVisible(is_maximized && maximizable);
  134. maximize_button_->SetVisible(!is_maximized && maximizable);
  135. // In touch mode, windows cannot be taken out of fullscreen or tiled mode, so
  136. // the maximize/restore button should be disabled, unless the window is not
  137. // maximized.
  138. const bool is_touch = ui::TouchUiController::Get()->touch_ui();
  139. restore_button_->SetEnabled(!is_touch);
  140. maximize_button_->SetEnabled(!is_touch || !is_maximized);
  141. // If the window isn't closable, the close button should be disabled.
  142. const bool closable = frame_view_->window()->IsClosable();
  143. close_button_->SetEnabled(closable);
  144. InvalidateLayout();
  145. }
  146. void WinCaptionButtonContainer::UpdateButtonToolTipsForWindowControlsOverlay() {
  147. minimize_button_->SetTooltipText(
  148. minimize_button_->GetViewAccessibility().GetCachedName());
  149. maximize_button_->SetTooltipText(
  150. maximize_button_->GetViewAccessibility().GetCachedName());
  151. restore_button_->SetTooltipText(
  152. restore_button_->GetViewAccessibility().GetCachedName());
  153. close_button_->SetTooltipText(
  154. close_button_->GetViewAccessibility().GetCachedName());
  155. }
  156. void WinCaptionButtonContainer::SetButtonSize(gfx::Size size) {
  157. minimize_button_->SetSize(size);
  158. maximize_button_->SetSize(size);
  159. restore_button_->SetSize(size);
  160. close_button_->SetSize(size);
  161. }
  162. BEGIN_METADATA(WinCaptionButtonContainer)
  163. END_METADATA
  164. } // namespace electron