terminal/src/host/selectionState.cpp

259 lines
8.3 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../types/inc/viewport.hpp"
using namespace Microsoft::Console::Types;
using namespace Microsoft::Console::Interactivity;
// Routine Description:
// - Determines whether the console is in a selecting state
// Arguments:
// - <none> (gets global state)
// Return Value:
// - True if the console is in a selecting state. False otherwise.
bool Selection::IsInSelectingState() const
{
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return WI_IsFlagSet(gci.Flags, CONSOLE_SELECTING);
}
// Routine Description:
// - Helps set the global selecting state.
// Arguments:
// - fSelectingOn - Set true to set the global flag on. False to turn the global flag off.
// Return Value:
// - <none>
void Selection::_SetSelectingState(const bool fSelectingOn)
{
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
WI_UpdateFlag(gci.Flags, CONSOLE_SELECTING, fSelectingOn);
}
// Routine Description:
// - Determines whether the console should do selections with the mouse
// a.k.a. "Quick Edit" mode
// Arguments:
// - <none> (gets global state)
// Return Value:
// - True if quick edit mode is enabled. False otherwise.
bool Selection::IsInQuickEditMode() const
{
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return WI_IsFlagSet(gci.Flags, CONSOLE_QUICK_EDIT_MODE);
}
// Routine Description:
// - Determines whether we are performing a line selection right now
// Arguments:
// - <none>
// Return Value:
// - True if the selection is to be treated line by line. False if it is to be a block.
bool Selection::IsLineSelection() const
{
// if line selection is on and alternate is off -OR-
// if line selection is off and alternate is on...
return (_fLineSelection != _fUseAlternateSelection);
}
// Routine Description:
// - Assures that the alternate selection flag is flipped in line with the requested format.
// If true, we'll align to ensure line selection is used. If false, we'll make sure box selection is used.
// Arguments:
// - fAlignToLineSelect - whether or not to use line selection
// Return Value:
// - <none>
void Selection::_AlignAlternateSelection(const bool fAlignToLineSelect)
{
if (fAlignToLineSelect)
{
// states are opposite when in line selection.
// e.g. Line = true, Alternate = false.
// and Line = false, Alternate = true.
_fUseAlternateSelection = !_fLineSelection;
}
else
{
// states are the same when in box selection.
// e.g. Line = true, Alternate = true.
// and Line = false, Alternate = false.
_fUseAlternateSelection = _fLineSelection;
}
}
// Routine Description:
// - Determines whether the selection area is empty.
// Arguments:
// - <none>
// Return Value:
// - True if the selection variables contain valid selection data. False otherwise.
bool Selection::IsAreaSelected() const
{
return WI_IsFlagSet(_dwSelectionFlags, CONSOLE_SELECTION_NOT_EMPTY);
}
// Routine Description:
// - Determines whether mark mode specifically started this selection.
// Arguments:
// - <none>
// Return Value:
// - True if the selection was started as mark mode. False otherwise.
bool Selection::IsKeyboardMarkSelection() const
{
return WI_IsFlagClear(_dwSelectionFlags, CONSOLE_MOUSE_SELECTION);
}
// Routine Description:
// - Determines whether a mouse event was responsible for initiating this selection.
// - This primarily refers to mouse drag in QuickEdit mode.
// - However, it refers to any non-mark-mode selection, whether the mouse actually started it or not.
// Arguments:
// - <none>
// Return Value:
// - True if the selection is mouse-initiated. False otherwise.
bool Selection::IsMouseInitiatedSelection() const
{
return WI_IsFlagSet(_dwSelectionFlags, CONSOLE_MOUSE_SELECTION);
}
// Routine Description:
// - Determines whether the mouse button is currently being held down
// to extend or otherwise manipulate the selection area.
// Arguments:
// - <none>
// Return Value:
// - True if the mouse button is currently down. False otherwise.
bool Selection::IsMouseButtonDown() const
{
return WI_IsFlagSet(_dwSelectionFlags, CONSOLE_MOUSE_DOWN);
}
void Selection::MouseDown()
{
WI_SetFlag(_dwSelectionFlags, CONSOLE_MOUSE_DOWN);
// We must capture the mouse on button down to ensure we receive messages if
// it comes back up outside the window.
IConsoleWindow* const pWindow = ServiceLocator::LocateConsoleWindow();
if (pWindow != nullptr)
{
pWindow->CaptureMouse();
}
}
void Selection::MouseUp()
{
WI_ClearFlag(_dwSelectionFlags, CONSOLE_MOUSE_DOWN);
IConsoleWindow* const pWindow = ServiceLocator::LocateConsoleWindow();
if (pWindow != nullptr)
{
pWindow->ReleaseMouse();
}
}
// Routine Description:
// - Saves the current cursor position data so it can be manipulated during selection.
// Arguments:
// - textBuffer - text buffer to set cursor data
// Return Value:
// - <none>
void Selection::_SaveCursorData(const Cursor& cursor) noexcept
{
_coordSavedCursorPosition = cursor.GetPosition();
_ulSavedCursorSize = cursor.GetSize();
_fSavedCursorVisible = cursor.IsVisible();
_savedCursorColor = cursor.GetColor();
_savedCursorType = cursor.GetType();
}
// Routine Description:
// - Restores the cursor position data that was captured when selection was started.
// Arguments:
// - <none> (Restores global state)
// Return Value:
// - <none>
void Selection::_RestoreDataToCursor(Cursor& cursor) noexcept
{
cursor.SetSize(_ulSavedCursorSize);
cursor.SetIsVisible(_fSavedCursorVisible);
cursor.SetColor(_savedCursorColor);
cursor.SetType(_savedCursorType);
cursor.SetIsOn(true);
cursor.SetPosition(_coordSavedCursorPosition);
}
// Routine Description:
// - Gets the current selection anchor position
// Arguments:
// - none
// Return Value:
// - current selection anchor
COORD Selection::GetSelectionAnchor() const noexcept
{
return _coordSelectionAnchor;
}
// Routine Description:
// - Gets the current selection rectangle
// Arguments:
// - none
// Return Value:
// - The rectangle to fill with selection data.
SMALL_RECT Selection::GetSelectionRectangle() const noexcept
{
return _srSelectionRect;
}
// Routine Description:
// - Gets the publicly facing set of selection flags.
// Strips out any internal flags in use.
// Arguments:
// - none
// Return Value:
// - The public selection flags
DWORD Selection::GetPublicSelectionFlags() const noexcept
{
// CONSOLE_SELECTION_VALID is the union (binary OR) of all externally valid flags in wincon.h
return (_dwSelectionFlags & CONSOLE_SELECTION_VALID);
}
// Routine Description:
// - Sets the line selection status.
// If true, we'll use line selection. If false, we'll use traditional box selection.
// Arguments:
// - fLineSelectionOn - whether or not to use line selection
// Return Value:
// - <none>
void Selection::SetLineSelection(const bool fLineSelectionOn)
{
if (_fLineSelection != fLineSelectionOn)
{
// Ensure any existing selections are cleared so the draw state is updated appropriately.
ClearSelection();
_fLineSelection = fLineSelectionOn;
}
}
// Routine Description:
// - checks if the selection can be changed by a mouse drag.
// - this is to allow double-click selection and click-mouse-drag selection to play nice together instead of
// the click-mouse-drag selection overwriting the double-click selection in case the user moves the mouse
// while double-clicking.
// Arguments:
// - mousePosition - current mouse position
// Return Value:
// - true if the selection can be changed by a mouse drag
bool Selection::ShouldAllowMouseDragSelection(const COORD mousePosition) const noexcept
{
const Viewport viewport = Viewport::FromInclusive(_srSelectionRect);
const bool selectionContainsMouse = viewport.IsInBounds(mousePosition);
return _allowMouseDragSelection || !selectionContainsMouse;
}