Commit ad22d8ad authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

capture_mode: Add UI for capture mode toggle button and close button

This is the first CL that implements the CaptureBarView. It only adds
the CaptureModeToggleButton, and the CaptureModeCloseButton, subsequent
CLs will build on these two views to implement the rest of the UI.

TBR=beccahughes@chromium.org
BUG=1112919

Change-Id: If9aca284bf419936df61ef0e285d1f143b06b0a0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2336021
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795728}
parent 3ee8ff30
...@@ -249,10 +249,16 @@ component("ash") { ...@@ -249,10 +249,16 @@ component("ash") {
"bluetooth_devices_observer.h", "bluetooth_devices_observer.h",
"cancel_mode.cc", "cancel_mode.cc",
"cancel_mode.h", "cancel_mode.h",
"capture_mode/capture_mode_close_button.cc",
"capture_mode/capture_mode_close_button.h",
"capture_mode/capture_mode_constants.h",
"capture_mode/capture_mode_controller.cc", "capture_mode/capture_mode_controller.cc",
"capture_mode/capture_mode_controller.h", "capture_mode/capture_mode_controller.h",
"capture_mode/capture_mode_feature_pod_controller.cc", "capture_mode/capture_mode_feature_pod_controller.cc",
"capture_mode/capture_mode_feature_pod_controller.h", "capture_mode/capture_mode_feature_pod_controller.h",
"capture_mode/capture_mode_toggle_button.cc",
"capture_mode/capture_mode_toggle_button.h",
"capture_mode/view_with_ink_drop.h",
"clipboard/clipboard_history.cc", "clipboard/clipboard_history.cc",
"clipboard/clipboard_history.h", "clipboard/clipboard_history.h",
"clipboard/clipboard_history_controller.cc", "clipboard/clipboard_history_controller.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/capture_mode/capture_mode_close_button.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/style/ash_color_provider.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/highlight_path_generator.h"
namespace ash {
CaptureModeCloseButton::CaptureModeCloseButton(views::ButtonListener* listener)
: ViewWithInkDrop(listener) {
SetPreferredSize(capture_mode::kButtonSize);
SetBorder(views::CreateEmptyBorder(capture_mode::kButtonPadding));
auto* color_provider = AshColorProvider::Get();
const SkColor normal_color = color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSystemMenuIconColor,
AshColorProvider::AshColorMode::kDark);
SetImage(views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(kCloseButtonIcon, normal_color));
SetImageHorizontalAlignment(ALIGN_CENTER);
SetImageVerticalAlignment(ALIGN_MIDDLE);
GetViewAccessibility().OverrideIsLeaf(true);
SetInstallFocusRingOnFocus(true);
SetFocusForPlatform();
focus_ring()->SetColor(color_provider->GetControlsLayerColor(
AshColorProvider::ControlsLayerType::kFocusRingColor,
AshColorProvider::AshColorMode::kDark));
focus_ring()->SetPathGenerator(
std::make_unique<views::CircleHighlightPathGenerator>(
capture_mode::kButtonPadding));
views::InstallCircleHighlightPathGenerator(this,
capture_mode::kButtonPadding);
}
const char* CaptureModeCloseButton::GetClassName() const {
return "CaptureModeCloseButton";
}
} // namespace ash
// Copyright 2020 The Chromium 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 ASH_CAPTURE_MODE_CAPTURE_MODE_CLOSE_BUTTON_H_
#define ASH_CAPTURE_MODE_CAPTURE_MODE_CLOSE_BUTTON_H_
#include "ash/capture_mode/view_with_ink_drop.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h"
namespace ash {
// A view that shows a close button which is part of the CaptureBarView.
class CaptureModeCloseButton : public ViewWithInkDrop<views::ImageButton> {
public:
explicit CaptureModeCloseButton(views::ButtonListener* listener);
CaptureModeCloseButton(const CaptureModeCloseButton&) = delete;
CaptureModeCloseButton& operator=(const CaptureModeCloseButton&) = delete;
~CaptureModeCloseButton() override = default;
// views::ImageButton:
const char* GetClassName() const override;
};
} // namespace ash
#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_CLOSE_BUTTON_H_
// Copyright 2020 The Chromium 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 ASH_CAPTURE_MODE_CAPTURE_MODE_CONSTANTS_H_
#define ASH_CAPTURE_MODE_CAPTURE_MODE_CONSTANTS_H_
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
namespace ash {
namespace capture_mode {
constexpr gfx::Size kButtonSize{32, 32};
constexpr gfx::Insets kButtonPadding{0};
constexpr float kInkDropVisibleOpacity = 0.2f;
constexpr float kInkDropHighlightVisibleOpacity = 0.3f;
constexpr SkColor kInkDropBaseColor = SK_ColorWHITE;
} // namespace capture_mode
} // namespace ash
#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_CONSTANTS_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/capture_mode/capture_mode_toggle_button.h"
#include "ash/style/ash_color_provider.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/highlight_path_generator.h"
namespace ash {
CaptureModeToggleButton::CaptureModeToggleButton(
views::ButtonListener* listener,
const gfx::VectorIcon& icon)
: ViewWithInkDrop(listener) {
SetPreferredSize(capture_mode::kButtonSize);
SetBorder(views::CreateEmptyBorder(capture_mode::kButtonPadding));
SetImageHorizontalAlignment(ALIGN_CENTER);
SetImageVerticalAlignment(ALIGN_MIDDLE);
GetViewAccessibility().OverrideIsLeaf(true);
SetInstallFocusRingOnFocus(true);
SetFocusForPlatform();
const auto* color_provider = AshColorProvider::Get();
focus_ring()->SetColor(color_provider->GetControlsLayerColor(
AshColorProvider::ControlsLayerType::kFocusRingColor,
AshColorProvider::AshColorMode::kDark));
focus_ring()->SetPathGenerator(
std::make_unique<views::CircleHighlightPathGenerator>(
capture_mode::kButtonPadding));
views::InstallCircleHighlightPathGenerator(this,
capture_mode::kButtonPadding);
SetIcon(icon);
toggled_background_color_ = color_provider->GetControlsLayerColor(
AshColorProvider::ControlsLayerType::kControlBackgroundColorActive,
AshColorProvider::AshColorMode::kDark);
}
const char* CaptureModeToggleButton::GetClassName() const {
return "CaptureModeToggleButton";
}
void CaptureModeToggleButton::OnPaintBackground(gfx::Canvas* canvas) {
if (!toggled())
return;
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setColor(toggled_background_color_);
const gfx::RectF bounds(GetContentsBounds());
canvas->DrawCircle(bounds.CenterPoint(), bounds.width() / 2, flags);
}
void CaptureModeToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
ImageButton::GetAccessibleNodeData(node_data);
node_data->SetName(GetTooltipText(gfx::Point()));
node_data->role = ax::mojom::Role::kToggleButton;
node_data->SetCheckedState(toggled() ? ax::mojom::CheckedState::kTrue
: ax::mojom::CheckedState::kFalse);
}
void CaptureModeToggleButton::SetIcon(const gfx::VectorIcon& icon) {
auto* color_provider = AshColorProvider::Get();
const SkColor normal_color = color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSystemMenuIconColor,
AshColorProvider::AshColorMode::kDark);
const SkColor toggled_color = color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSystemMenuIconColorToggled,
AshColorProvider::AshColorMode::kDark);
SetImage(views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(icon, normal_color));
const auto toggled_icon = gfx::CreateVectorIcon(icon, toggled_color);
SetToggledImage(views::Button::STATE_NORMAL, &toggled_icon);
}
} // namespace ash
// Copyright 2020 The Chromium 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 ASH_CAPTURE_MODE_CAPTURE_MODE_TOGGLE_BUTTON_H_
#define ASH_CAPTURE_MODE_CAPTURE_MODE_TOGGLE_BUTTON_H_
#include "ash/capture_mode/view_with_ink_drop.h"
#include "ui/views/controls/button/image_button.h"
namespace gfx {
struct VectorIcon;
} // namespace gfx
namespace ash {
// A toggle button that will be used in the sub views of the CaptureBarView to
// toggle between image and video capture, and between fullscreen, window, and
// region capture sources.
class CaptureModeToggleButton
: public ViewWithInkDrop<views::ToggleImageButton> {
public:
CaptureModeToggleButton(views::ButtonListener* listener,
const gfx::VectorIcon& icon);
CaptureModeToggleButton(const CaptureModeToggleButton&) = delete;
CaptureModeToggleButton& operator=(const CaptureModeToggleButton&) = delete;
~CaptureModeToggleButton() override = default;
// views::ToggleImageButton:
const char* GetClassName() const override;
void OnPaintBackground(gfx::Canvas* canvas) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
private:
// Called by the constructor to set the icon in both normal and toggled
// states.
void SetIcon(const gfx::VectorIcon& icon);
// The color of the button background when the button is in a toggled state.
SkColor toggled_background_color_;
};
} // namespace ash
#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_TOGGLE_BUTTON_H_
// Copyright 2020 The Chromium 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 ASH_CAPTURE_MODE_VIEW_WITH_INK_DROP_H_
#define ASH_CAPTURE_MODE_VIEW_WITH_INK_DROP_H_
#include <type_traits>
#include "ash/capture_mode/capture_mode_constants.h"
#include "ui/views/animation/ink_drop_host_view.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/style/platform_style.h"
namespace ash {
// A template class that relieves us from having to rewrite the ink drop boiler-
// plate code for all the Capture Mode views that will need it. This is used by
// CaptureModeToggleButton, CaptureModeCloseButton, ... etc.
// |T| must be a subtype of |views::InkDropHostView|.
template <typename T>
class ViewWithInkDrop : public T {
public:
static_assert(std::is_base_of<views::InkDropHostView, T>::value,
"T must be a subtype of views::InkDropHostView");
// A constructor that forwards |args| to |T|'s constructor, so |args| are the
// exact same as required by |T|'s constructor. It sets up the ink drop on the
// view.
template <typename... Args>
explicit ViewWithInkDrop(Args... args) : T(std::forward<Args>(args)...) {
T::SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
T::set_has_ink_drop_action_on_click(true);
T::set_ink_drop_visible_opacity(capture_mode::kInkDropVisibleOpacity);
}
~ViewWithInkDrop() override = default;
// views::InkDropHostView:
std::unique_ptr<views::InkDrop> CreateInkDrop() override {
auto ink_drop = T::CreateDefaultFloodFillInkDropImpl();
ink_drop->SetShowHighlightOnHover(false);
ink_drop->SetShowHighlightOnFocus(!views::PlatformStyle::kPreferFocusRings);
return std::move(ink_drop);
}
std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
const override {
auto highlight = std::make_unique<views::InkDropHighlight>(
gfx::SizeF(T::size()), GetInkDropBaseColor());
highlight->set_visible_opacity(
capture_mode::kInkDropHighlightVisibleOpacity);
return highlight;
}
SkColor GetInkDropBaseColor() const override {
return capture_mode::kInkDropBaseColor;
}
};
} // namespace ash
#endif // ASH_CAPTURE_MODE_VIEW_WITH_INK_DROP_H_
...@@ -127,7 +127,7 @@ TEST_F(LoginPasswordViewTestFeatureEnabled, ...@@ -127,7 +127,7 @@ TEST_F(LoginPasswordViewTestFeatureEnabled,
// The display password button is not toggled by default and the password is // The display password button is not toggled by default and the password is
// not visible. // not visible.
EXPECT_FALSE(test_api.display_password_button()->toggled_for_testing()); EXPECT_FALSE(test_api.display_password_button()->toggled());
EXPECT_EQ(test_api.textfield()->GetTextInputType(), EXPECT_EQ(test_api.textfield()->GetTextInputType(),
ui::TEXT_INPUT_TYPE_PASSWORD); ui::TEXT_INPUT_TYPE_PASSWORD);
...@@ -136,7 +136,7 @@ TEST_F(LoginPasswordViewTestFeatureEnabled, ...@@ -136,7 +136,7 @@ TEST_F(LoginPasswordViewTestFeatureEnabled,
generator->MoveMouseTo( generator->MoveMouseTo(
test_api.display_password_button()->GetBoundsInScreen().CenterPoint()); test_api.display_password_button()->GetBoundsInScreen().CenterPoint());
generator->ClickLeftButton(); generator->ClickLeftButton();
EXPECT_FALSE(test_api.display_password_button()->toggled_for_testing()); EXPECT_FALSE(test_api.display_password_button()->toggled());
EXPECT_EQ(test_api.textfield()->GetTextInputType(), EXPECT_EQ(test_api.textfield()->GetTextInputType(),
ui::TEXT_INPUT_TYPE_PASSWORD); ui::TEXT_INPUT_TYPE_PASSWORD);
...@@ -145,14 +145,14 @@ TEST_F(LoginPasswordViewTestFeatureEnabled, ...@@ -145,14 +145,14 @@ TEST_F(LoginPasswordViewTestFeatureEnabled,
generator->MoveMouseTo( generator->MoveMouseTo(
test_api.display_password_button()->GetBoundsInScreen().CenterPoint()); test_api.display_password_button()->GetBoundsInScreen().CenterPoint());
generator->ClickLeftButton(); generator->ClickLeftButton();
EXPECT_TRUE(test_api.display_password_button()->toggled_for_testing()); EXPECT_TRUE(test_api.display_password_button()->toggled());
EXPECT_EQ(test_api.textfield()->GetTextInputType(), ui::TEXT_INPUT_TYPE_NULL); EXPECT_EQ(test_api.textfield()->GetTextInputType(), ui::TEXT_INPUT_TYPE_NULL);
// Click the display password button again. The password should be hidden. // Click the display password button again. The password should be hidden.
generator->MoveMouseTo( generator->MoveMouseTo(
test_api.display_password_button()->GetBoundsInScreen().CenterPoint()); test_api.display_password_button()->GetBoundsInScreen().CenterPoint());
generator->ClickLeftButton(); generator->ClickLeftButton();
EXPECT_FALSE(test_api.display_password_button()->toggled_for_testing()); EXPECT_FALSE(test_api.display_password_button()->toggled());
EXPECT_EQ(test_api.textfield()->GetTextInputType(), EXPECT_EQ(test_api.textfield()->GetTextInputType(),
ui::TEXT_INPUT_TYPE_PASSWORD); ui::TEXT_INPUT_TYPE_PASSWORD);
} }
......
...@@ -32,9 +32,9 @@ aggregate_vector_icons("ash_vector_icons") { ...@@ -32,9 +32,9 @@ aggregate_vector_icons("ash_vector_icons") {
"captive_portal.icon", "captive_portal.icon",
"capture_mode.icon", "capture_mode.icon",
"check_circle.icon", "check_circle.icon",
"close_button.icon",
"custom_data.icon", "custom_data.icon",
"delete.icon", "delete.icon",
"desks_close_desk_button.icon",
"desks_new_desk_button.icon", "desks_new_desk_button.icon",
"dictation_menu.icon", "dictation_menu.icon",
"dictation_off.icon", "dictation_off.icon",
......
...@@ -32,7 +32,7 @@ CloseDeskButton::CloseDeskButton(views::ButtonListener* listener) ...@@ -32,7 +32,7 @@ CloseDeskButton::CloseDeskButton(views::ButtonListener* listener)
color_provider->DecorateCloseButton( color_provider->DecorateCloseButton(
this, AshColorProvider::ButtonType::kCloseButtonWithSmallBase, this, AshColorProvider::ButtonType::kCloseButtonWithSmallBase,
AshColorProvider::AshColorMode::kDark, kCloseButtonSize, AshColorProvider::AshColorMode::kDark, kCloseButtonSize,
kDesksCloseDeskButtonIcon); kCloseButtonIcon);
AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::RippleAttributes ripple_attributes =
color_provider->GetRippleAttributes(background()->get_color()); color_provider->GetRippleAttributes(background()->get_color());
......
...@@ -539,7 +539,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, PlayToggle_FromObserver_Empty) { ...@@ -539,7 +539,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, PlayToggle_FromObserver_Empty) {
views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>( views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>(
GetButtonForAction(MediaSessionAction::kPlay)); GetButtonForAction(MediaSessionAction::kPlay));
ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName()); ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
EXPECT_FALSE(button->toggled_for_testing()); EXPECT_FALSE(button->toggled());
} }
view()->UpdateWithMediaSessionInfo( view()->UpdateWithMediaSessionInfo(
...@@ -549,7 +549,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, PlayToggle_FromObserver_Empty) { ...@@ -549,7 +549,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, PlayToggle_FromObserver_Empty) {
views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>( views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>(
GetButtonForAction(MediaSessionAction::kPlay)); GetButtonForAction(MediaSessionAction::kPlay));
ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName()); ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
EXPECT_FALSE(button->toggled_for_testing()); EXPECT_FALSE(button->toggled());
} }
} }
...@@ -562,7 +562,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, ...@@ -562,7 +562,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest,
views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>( views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>(
GetButtonForAction(MediaSessionAction::kPlay)); GetButtonForAction(MediaSessionAction::kPlay));
ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName()); ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
EXPECT_FALSE(button->toggled_for_testing()); EXPECT_FALSE(button->toggled());
} }
media_session::mojom::MediaSessionInfoPtr session_info( media_session::mojom::MediaSessionInfoPtr session_info(
...@@ -576,7 +576,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, ...@@ -576,7 +576,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest,
views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>( views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>(
GetButtonForAction(MediaSessionAction::kPause)); GetButtonForAction(MediaSessionAction::kPause));
ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName()); ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
EXPECT_TRUE(button->toggled_for_testing()); EXPECT_TRUE(button->toggled());
} }
session_info->playback_state = session_info->playback_state =
...@@ -587,7 +587,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest, ...@@ -587,7 +587,7 @@ TEST_F(MAYBE_MediaNotificationViewImplTest,
views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>( views::ToggleImageButton* button = static_cast<views::ToggleImageButton*>(
GetButtonForAction(MediaSessionAction::kPlay)); GetButtonForAction(MediaSessionAction::kPlay));
ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName()); ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
EXPECT_FALSE(button->toggled_for_testing()); EXPECT_FALSE(button->toggled());
} }
} }
......
...@@ -299,10 +299,6 @@ void ToggleImageButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { ...@@ -299,10 +299,6 @@ void ToggleImageButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
} }
} }
bool ToggleImageButton::toggled_for_testing() const {
return toggled_;
}
DEFINE_ENUM_CONVERTERS(ImageButton::HorizontalAlignment, DEFINE_ENUM_CONVERTERS(ImageButton::HorizontalAlignment,
{ImageButton::HorizontalAlignment::ALIGN_LEFT, {ImageButton::HorizontalAlignment::ALIGN_LEFT,
base::ASCIIToUTF16("ALIGN_LEFT")}, base::ASCIIToUTF16("ALIGN_LEFT")},
......
...@@ -122,6 +122,8 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton { ...@@ -122,6 +122,8 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
explicit ToggleImageButton(ButtonListener* listener); explicit ToggleImageButton(ButtonListener* listener);
~ToggleImageButton() override; ~ToggleImageButton() override;
bool toggled() const { return toggled_; }
// Change the toggled state. // Change the toggled state.
void SetToggled(bool toggled); void SetToggled(bool toggled);
...@@ -144,8 +146,6 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton { ...@@ -144,8 +146,6 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
base::string16 GetTooltipText(const gfx::Point& p) const override; base::string16 GetTooltipText(const gfx::Point& p) const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool toggled_for_testing() const;
private: private:
// The parent class's images_ member is used for the current images, // The parent class's images_ member is used for the current images,
// and this array is used to hold the alternative images. // and this array is used to hold the alternative images.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment