mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 18:43:54 -06:00
Background image support (#853)
* Initial code check in for background images * Cleaning up whitespace * Whitespace cleanup * Added/fixed comments * Fixing tabs * Reverting erroneous file add * Removing custom enum for image stretching mode and using Windows::UI::Xaml::Media::Stretch instead. * Removing now-superfluous static_cast when setting stretch mode. * Updating code to use wstring_view (per #925) * One last set of wstring -> wstring_view changes * Split off brush-intialization function from TermControl::_BackgroundColorChanged and added code to prevent flicker on resetting acrylic or image backgrounds.
This commit is contained in:
parent
2f88c46350
commit
097f7d32a6
@ -12,7 +12,6 @@ using namespace winrt::TerminalApp;
|
||||
using namespace winrt::Windows::Data::Json;
|
||||
using namespace ::Microsoft::Console;
|
||||
|
||||
|
||||
static constexpr std::wstring_view NAME_KEY{ L"name" };
|
||||
static constexpr std::wstring_view GUID_KEY{ L"guid" };
|
||||
static constexpr std::wstring_view COLORSCHEME_KEY{ L"colorscheme" };
|
||||
@ -36,6 +35,9 @@ static constexpr std::wstring_view CLOSEONEXIT_KEY{ L"closeOnExit" };
|
||||
static constexpr std::wstring_view PADDING_KEY{ L"padding" };
|
||||
static constexpr std::wstring_view STARTINGDIRECTORY_KEY{ L"startingDirectory" };
|
||||
static constexpr std::wstring_view ICON_KEY{ L"icon" };
|
||||
static constexpr std::wstring_view BACKGROUNDIMAGE_KEY{ L"backgroundImage" };
|
||||
static constexpr std::wstring_view BACKGROUNDIMAGEOPACITY_KEY{ L"backgroundImageOpacity" };
|
||||
static constexpr std::wstring_view BACKGROUNDIMAGESTRETCHMODE_KEY{ L"backgroundImageStretchMode" };
|
||||
|
||||
// Possible values for Scrollbar state
|
||||
static constexpr std::wstring_view ALWAYS_VISIBLE{ L"visible" };
|
||||
@ -48,6 +50,12 @@ static constexpr std::wstring_view CURSORSHAPE_UNDERSCORE{ L"underscore" };
|
||||
static constexpr std::wstring_view CURSORSHAPE_FILLEDBOX{ L"filledBox" };
|
||||
static constexpr std::wstring_view CURSORSHAPE_EMPTYBOX{ L"emptyBox" };
|
||||
|
||||
// Possible values for Image Stretch Mode
|
||||
static constexpr std::wstring_view IMAGESTRETCHMODE_NONE{ L"none" };
|
||||
static constexpr std::wstring_view IMAGESTRETCHMODE_FILL{ L"fill" };
|
||||
static constexpr std::wstring_view IMAGESTRETCHMODE_UNIFORM{ L"uniform" };
|
||||
static constexpr std::wstring_view IMAGESTRETCHMODE_UNIFORMTOFILL{ L"uniformToFill" };
|
||||
|
||||
Profile::Profile() :
|
||||
Profile(Utils::CreateGuid())
|
||||
{
|
||||
@ -76,7 +84,10 @@ Profile::Profile(const winrt::guid& guid):
|
||||
_scrollbarState{ },
|
||||
_closeOnExit{ true },
|
||||
_padding{ DEFAULT_PADDING },
|
||||
_icon{ }
|
||||
_icon{ },
|
||||
_backgroundImage{ },
|
||||
_backgroundImageOpacity{ },
|
||||
_backgroundImageStretchMode{ }
|
||||
{
|
||||
}
|
||||
|
||||
@ -173,6 +184,21 @@ TerminalSettings Profile::CreateTerminalSettings(const std::vector<ColorScheme>&
|
||||
terminalSettings.ScrollState(result);
|
||||
}
|
||||
|
||||
if (_backgroundImage)
|
||||
{
|
||||
terminalSettings.BackgroundImage(_backgroundImage.value());
|
||||
}
|
||||
|
||||
if (_backgroundImageOpacity)
|
||||
{
|
||||
terminalSettings.BackgroundImageOpacity(_backgroundImageOpacity.value());
|
||||
}
|
||||
|
||||
if (_backgroundImageStretchMode)
|
||||
{
|
||||
terminalSettings.BackgroundImageStretchMode(_backgroundImageStretchMode.value());
|
||||
}
|
||||
|
||||
return terminalSettings;
|
||||
}
|
||||
|
||||
@ -274,6 +300,25 @@ JsonObject Profile::ToJson() const
|
||||
jsonObject.Insert(ICON_KEY, icon);
|
||||
}
|
||||
|
||||
if (_backgroundImage)
|
||||
{
|
||||
const auto backgroundImage = JsonValue::CreateStringValue(_backgroundImage.value());
|
||||
jsonObject.Insert(BACKGROUNDIMAGE_KEY, backgroundImage);
|
||||
}
|
||||
|
||||
if (_backgroundImageOpacity)
|
||||
{
|
||||
const auto opacity = JsonValue::CreateNumberValue(_backgroundImageOpacity.value());
|
||||
jsonObject.Insert(BACKGROUNDIMAGEOPACITY_KEY, opacity);
|
||||
}
|
||||
|
||||
if (_backgroundImageStretchMode)
|
||||
{
|
||||
const auto imageStretchMode = JsonValue::CreateStringValue(
|
||||
SerializeImageStretchMode(_backgroundImageStretchMode.value()));
|
||||
jsonObject.Insert(BACKGROUNDIMAGESTRETCHMODE_KEY, imageStretchMode);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
@ -405,6 +450,19 @@ Profile Profile::FromJson(winrt::Windows::Data::Json::JsonObject json)
|
||||
{
|
||||
result._icon = json.GetNamedString(ICON_KEY);
|
||||
}
|
||||
if (json.HasKey(BACKGROUNDIMAGE_KEY))
|
||||
{
|
||||
result._backgroundImage = json.GetNamedString(BACKGROUNDIMAGE_KEY);
|
||||
}
|
||||
if (json.HasKey(BACKGROUNDIMAGEOPACITY_KEY))
|
||||
{
|
||||
result._backgroundImageOpacity = json.GetNamedNumber(BACKGROUNDIMAGEOPACITY_KEY);
|
||||
}
|
||||
if (json.HasKey(BACKGROUNDIMAGESTRETCHMODE_KEY))
|
||||
{
|
||||
const auto stretchMode = json.GetNamedString(BACKGROUNDIMAGESTRETCHMODE_KEY);
|
||||
result._backgroundImageStretchMode = ParseImageStretchMode(stretchMode.c_str());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -551,6 +609,58 @@ ScrollbarState Profile::ParseScrollbarState(const std::wstring& scrollbarState)
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for converting a user-specified image stretch mode
|
||||
// to the appropriate enum value
|
||||
// Arguments:
|
||||
// - The value from the profiles.json file
|
||||
// Return Value:
|
||||
// - The corresponding enum value which maps to the string provided by the user
|
||||
winrt::Windows::UI::Xaml::Media::Stretch Profile::ParseImageStretchMode(const std::wstring& imageStretchMode)
|
||||
{
|
||||
if (imageStretchMode == IMAGESTRETCHMODE_NONE)
|
||||
{
|
||||
return winrt::Windows::UI::Xaml::Media::Stretch::None;
|
||||
}
|
||||
else if (imageStretchMode == IMAGESTRETCHMODE_FILL)
|
||||
{
|
||||
return winrt::Windows::UI::Xaml::Media::Stretch::Fill;
|
||||
}
|
||||
else if (imageStretchMode == IMAGESTRETCHMODE_UNIFORM)
|
||||
{
|
||||
return winrt::Windows::UI::Xaml::Media::Stretch::Uniform;
|
||||
}
|
||||
else // Fall through to default behavior
|
||||
{
|
||||
return winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for converting an ImageStretchMode to the
|
||||
// correct string value.
|
||||
// Arguments:
|
||||
// - imageStretchMode: The enum value to convert to a string.
|
||||
// Return Value:
|
||||
// - The string value for the given ImageStretchMode
|
||||
std::wstring_view Profile::SerializeImageStretchMode(const winrt::Windows::UI::Xaml::Media::Stretch imageStretchMode)
|
||||
{
|
||||
switch (imageStretchMode)
|
||||
{
|
||||
case winrt::Windows::UI::Xaml::Media::Stretch::None:
|
||||
return IMAGESTRETCHMODE_NONE;
|
||||
case winrt::Windows::UI::Xaml::Media::Stretch::Fill:
|
||||
return IMAGESTRETCHMODE_FILL;
|
||||
case winrt::Windows::UI::Xaml::Media::Stretch::Uniform:
|
||||
return IMAGESTRETCHMODE_UNIFORM;
|
||||
default:
|
||||
case winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill:
|
||||
return IMAGESTRETCHMODE_UNIFORMTOFILL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for converting a user-specified cursor style corresponding
|
||||
// CursorStyle enum value
|
||||
|
||||
@ -59,6 +59,8 @@ private:
|
||||
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
|
||||
|
||||
static winrt::Microsoft::Terminal::Settings::ScrollbarState ParseScrollbarState(const std::wstring& scrollbarState);
|
||||
static winrt::Windows::UI::Xaml::Media::Stretch ParseImageStretchMode(const std::wstring& imageStretchMode);
|
||||
static std::wstring_view SerializeImageStretchMode(const winrt::Windows::UI::Xaml::Media::Stretch imageStretchMode);
|
||||
static winrt::Microsoft::Terminal::Settings::CursorStyle _ParseCursorShape(const std::wstring& cursorShapeString);
|
||||
static std::wstring_view _SerializeCursorStyle(const winrt::Microsoft::Terminal::Settings::CursorStyle cursorShape);
|
||||
|
||||
@ -84,6 +86,10 @@ private:
|
||||
double _acrylicTransparency;
|
||||
bool _useAcrylic;
|
||||
|
||||
std::optional<std::wstring> _backgroundImage;
|
||||
std::optional<double> _backgroundImageOpacity;
|
||||
std::optional<winrt::Windows::UI::Xaml::Media::Stretch> _backgroundImageStretchMode;
|
||||
|
||||
std::optional<std::wstring> _scrollbarState;
|
||||
bool _closeOnExit;
|
||||
std::wstring _padding;
|
||||
|
||||
@ -158,6 +158,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - Style our UI elements based on the values in our _settings, and set up
|
||||
// other control-specific settings. This method will be called whenever
|
||||
// the settings are reloaded.
|
||||
// * Calls _InitializeBackgroundBrush to set up the Xaml brush responsible
|
||||
// for the control's background
|
||||
// * Calls _BackgroundColorChanged to style the background of the control
|
||||
// - Core settings will be passed to the terminal in _InitializeTerminal
|
||||
// Arguments:
|
||||
@ -166,6 +168,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - <none>
|
||||
void TermControl::_ApplyUISettings()
|
||||
{
|
||||
_InitializeBackgroundBrush();
|
||||
|
||||
uint32_t bg = _settings.DefaultBackground();
|
||||
_BackgroundColorChanged(bg);
|
||||
|
||||
@ -186,9 +190,96 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
_desiredFont = { _actualFont };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set up the brush used to display the control's background.
|
||||
// - Respects the settings for acrylic, background image and opacity from
|
||||
// _settings.
|
||||
// * Prioritizes the acrylic background if chosen, respecting acrylicOpacity
|
||||
// from _settings.
|
||||
// * If acrylic is not enabled and a backgroundImage is present, it is used,
|
||||
// respecting the opacity and stretch mode settings from _settings.
|
||||
// * Falls back to a solid color background from _settings if acrylic is not
|
||||
// enabled and no background image is present.
|
||||
// - Avoids image flickering and acrylic brush redraw if settings are changed
|
||||
// but the appropriate brush is still in place.
|
||||
// - Does not apply background color; _BackgroundColorChanged must be called
|
||||
// to do so.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TermControl::_InitializeBackgroundBrush()
|
||||
{
|
||||
if (_settings.UseAcrylic())
|
||||
{
|
||||
// See if we've already got an acrylic background brush
|
||||
// to avoid the flicker when setting up a new one
|
||||
auto acrylic = _root.Background().try_as<Media::AcrylicBrush>();
|
||||
|
||||
// Instantiate a brush if there's not already one there
|
||||
if (acrylic == nullptr)
|
||||
{
|
||||
acrylic = Media::AcrylicBrush{};
|
||||
acrylic.BackgroundSource(Media::AcrylicBackgroundSource::HostBackdrop);
|
||||
}
|
||||
|
||||
// Apply brush settings
|
||||
acrylic.TintOpacity(_settings.TintOpacity());
|
||||
|
||||
// Apply brush to control if it's not already there
|
||||
if (_root.Background() != acrylic)
|
||||
{
|
||||
_root.Background(acrylic);
|
||||
}
|
||||
}
|
||||
else if (!_settings.BackgroundImage().empty())
|
||||
{
|
||||
Windows::Foundation::Uri imageUri{ _settings.BackgroundImage() };
|
||||
|
||||
// Check if the existing brush is an image brush, and if not
|
||||
// construct a new one
|
||||
auto brush = _root.Background().try_as<Media::ImageBrush>();
|
||||
|
||||
if (brush == nullptr)
|
||||
{
|
||||
brush = Media::ImageBrush{};
|
||||
}
|
||||
|
||||
// Check if the image brush is already pointing to the image
|
||||
// in the modified settings; if it isn't (or isn't there),
|
||||
// set a new image source for the brush
|
||||
auto imageSource = brush.ImageSource().try_as<Media::Imaging::BitmapImage>();
|
||||
|
||||
if (imageSource == nullptr || imageSource.UriSource() == nullptr
|
||||
|| imageSource.UriSource().RawUri() != imageUri.RawUri())
|
||||
{
|
||||
// Note that BitmapImage handles the image load asynchronously,
|
||||
// which is especially important since the image
|
||||
// may well be both large and somewhere out on the
|
||||
// internet.
|
||||
Media::Imaging::BitmapImage image(imageUri);
|
||||
brush.ImageSource(image);
|
||||
}
|
||||
|
||||
// Apply stretch and opacity settings
|
||||
brush.Stretch(_settings.BackgroundImageStretchMode());
|
||||
brush.Opacity(_settings.BackgroundImageOpacity());
|
||||
|
||||
// Apply brush if it isn't already there
|
||||
if (_root.Background() != brush)
|
||||
{
|
||||
_root.Background(brush);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Media::SolidColorBrush solidColor{};
|
||||
_root.Background(solidColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Style the background of the control with the provided background color
|
||||
// - Respects the settings for acrylic and opacity from _settings
|
||||
// Arguments:
|
||||
// - color: The background color to use as a uint32 (aka DWORD COLORREF)
|
||||
// Return Value:
|
||||
@ -208,23 +299,33 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
if (_settings.UseAcrylic())
|
||||
{
|
||||
Media::AcrylicBrush acrylic{};
|
||||
acrylic.BackgroundSource(Media::AcrylicBackgroundSource::HostBackdrop);
|
||||
acrylic.FallbackColor(bgColor);
|
||||
acrylic.TintColor(bgColor);
|
||||
acrylic.TintOpacity(_settings.TintOpacity());
|
||||
_root.Background(acrylic);
|
||||
if (auto acrylic = _root.Background().try_as<Media::AcrylicBrush>())
|
||||
{
|
||||
acrylic.FallbackColor(bgColor);
|
||||
acrylic.TintColor(bgColor);
|
||||
}
|
||||
|
||||
// If we're acrylic, we want to make sure that the default BG color
|
||||
// is transparent, so we can see the acrylic effect on text with the
|
||||
// default BG color.
|
||||
_settings.DefaultBackground(ARGB(0, R, G, B));
|
||||
}
|
||||
else if (!_settings.BackgroundImage().empty())
|
||||
{
|
||||
// This currently applies no changes to the image background
|
||||
// brush itself.
|
||||
|
||||
// Set the default background as transparent to prevent the
|
||||
// DX layer from overwriting the background image
|
||||
_settings.DefaultBackground(ARGB(0, R, G, B));
|
||||
}
|
||||
else
|
||||
{
|
||||
Media::SolidColorBrush solidColor{};
|
||||
solidColor.Color(bgColor);
|
||||
_root.Background(solidColor);
|
||||
if (auto solidColor = _root.Background().try_as<Media::SolidColorBrush>())
|
||||
{
|
||||
solidColor.Color(bgColor);
|
||||
}
|
||||
|
||||
_settings.DefaultBackground(RGB(R, G, B));
|
||||
}
|
||||
});
|
||||
|
||||
@ -95,6 +95,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
void _Create();
|
||||
void _ApplyUISettings();
|
||||
void _InitializeBackgroundBrush();
|
||||
void _BackgroundColorChanged(const uint32_t color);
|
||||
void _ApplyConnectionSettings();
|
||||
void _InitializeTerminal();
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.ui.xaml.media.imaging.h>
|
||||
#include <winrt/Windows.ui.xaml.input.h>
|
||||
|
||||
#include <windows.ui.xaml.media.dxinterop.h>
|
||||
|
||||
@ -34,5 +34,8 @@ namespace Microsoft.Terminal.Settings
|
||||
String StartingDirectory;
|
||||
String EnvironmentVariables;
|
||||
|
||||
String BackgroundImage;
|
||||
Double BackgroundImageOpacity;
|
||||
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
||||
};
|
||||
}
|
||||
|
||||
@ -26,6 +26,9 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
|
||||
_padding{ DEFAULT_PADDING },
|
||||
_fontFace{ DEFAULT_FONT_FACE },
|
||||
_fontSize{ DEFAULT_FONT_SIZE },
|
||||
_backgroundImage{},
|
||||
_backgroundImageOpacity{ 1.0 },
|
||||
_backgroundImageStretchMode{ winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill },
|
||||
_keyBindings{ nullptr },
|
||||
_scrollbarState{ ScrollbarState::Visible }
|
||||
{
|
||||
@ -193,6 +196,36 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
|
||||
_fontSize = value;
|
||||
}
|
||||
|
||||
void TerminalSettings::BackgroundImage(hstring const& value)
|
||||
{
|
||||
_backgroundImage = value;
|
||||
}
|
||||
|
||||
hstring TerminalSettings::BackgroundImage()
|
||||
{
|
||||
return _backgroundImage;
|
||||
}
|
||||
|
||||
void TerminalSettings::BackgroundImageOpacity(double value)
|
||||
{
|
||||
_backgroundImageOpacity = value;
|
||||
}
|
||||
|
||||
double TerminalSettings::BackgroundImageOpacity()
|
||||
{
|
||||
return _backgroundImageOpacity;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Stretch TerminalSettings::BackgroundImageStretchMode()
|
||||
{
|
||||
return _backgroundImageStretchMode;
|
||||
}
|
||||
|
||||
void TerminalSettings::BackgroundImageStretchMode(winrt::Windows::UI::Xaml::Media::Stretch value)
|
||||
{
|
||||
_backgroundImageStretchMode = value;
|
||||
}
|
||||
|
||||
Settings::IKeyBindings TerminalSettings::KeyBindings()
|
||||
{
|
||||
return _keyBindings;
|
||||
|
||||
@ -61,6 +61,13 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
|
||||
int32_t FontSize();
|
||||
void FontSize(int32_t value);
|
||||
|
||||
hstring BackgroundImage();
|
||||
void BackgroundImage(hstring const& value);
|
||||
double BackgroundImageOpacity();
|
||||
void BackgroundImageOpacity(double value);
|
||||
winrt::Windows::UI::Xaml::Media::Stretch BackgroundImageStretchMode();
|
||||
void BackgroundImageStretchMode(winrt::Windows::UI::Xaml::Media::Stretch value);
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::IKeyBindings KeyBindings();
|
||||
void KeyBindings(winrt::Microsoft::Terminal::Settings::IKeyBindings const& value);
|
||||
|
||||
@ -94,6 +101,9 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
|
||||
hstring _fontFace;
|
||||
int32_t _fontSize;
|
||||
hstring _padding;
|
||||
hstring _backgroundImage;
|
||||
double _backgroundImageOpacity;
|
||||
winrt::Windows::UI::Xaml::Media::Stretch _backgroundImageStretchMode;
|
||||
hstring _commandline;
|
||||
hstring _startingDir;
|
||||
hstring _envVars;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user