192 lines
6.9 KiB
C++
192 lines
6.9 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
//
|
|
// Contents: UI formatted text editor.
|
|
//
|
|
// Usage: Type to edit text.
|
|
// Arrow keys move, +shift selects, +ctrl moves whole word
|
|
// Left drag selects.
|
|
// Middle drag pans.
|
|
// Scroll wheel scrolls, +shift for horizontal, +ctrl zooms.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#pragma once
|
|
|
|
|
|
class DECLSPEC_UUID("2EF2C6E3-5352-41c1-89D0-1C7F7F99359B") TextEditor
|
|
: public ComBase<QiList<IUnknown> >
|
|
{
|
|
public:
|
|
enum SetSelectionMode
|
|
{
|
|
SetSelectionModeLeft, // cluster left
|
|
SetSelectionModeRight, // cluster right
|
|
SetSelectionModeUp, // line up
|
|
SetSelectionModeDown, // line down
|
|
SetSelectionModeLeftChar, // single character left (backspace uses it)
|
|
SetSelectionModeRightChar, // single character right
|
|
SetSelectionModeLeftWord, // single word left
|
|
SetSelectionModeRightWord, // single word right
|
|
SetSelectionModeHome, // front of line
|
|
SetSelectionModeEnd, // back of line
|
|
SetSelectionModeFirst, // very first position
|
|
SetSelectionModeLast, // very last position
|
|
SetSelectionModeAbsoluteLeading, // explicit position (for mouse click)
|
|
SetSelectionModeAbsoluteTrailing, // explicit position, trailing edge
|
|
SetSelectionModeAll // select all text
|
|
};
|
|
|
|
public:
|
|
////////////////////
|
|
// Creation/destruction
|
|
TextEditor(IDWriteFactory* factory);
|
|
HRESULT static Create(
|
|
HWND parentHwnd,
|
|
const wchar_t* text,
|
|
IDWriteTextFormat* textFormat,
|
|
IDWriteFactory* factory,
|
|
OUT TextEditor** textEditor
|
|
);
|
|
|
|
~TextEditor()
|
|
{
|
|
SafeRelease(&textLayout_);
|
|
SafeRelease(&renderTarget_);
|
|
SafeRelease(&pageBackgroundEffect_);
|
|
SafeRelease(&textSelectionEffect_);
|
|
SafeRelease(&imageSelectionEffect_);
|
|
SafeRelease(&caretBackgroundEffect_);
|
|
}
|
|
|
|
static ATOM RegisterWindowClass();
|
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
HWND GetHwnd() {return hwnd_;}
|
|
void OnDestroy();
|
|
|
|
////////////////////
|
|
// Input dispatch
|
|
void OnMousePress(UINT message, float x, float y);
|
|
void OnMouseRelease(UINT message, float x, float y);
|
|
void OnMouseMove(float x, float y);
|
|
void OnMouseScroll(float xScroll, float yScroll);
|
|
void OnMouseExit();
|
|
void OnKeyPress(UINT32 keyCode);
|
|
void OnKeyCharacter(UINT32 charCode);
|
|
void MirrorXCoordinate(IN OUT float& x);
|
|
|
|
////////////////////
|
|
// Drawing/view change
|
|
void OnDraw();
|
|
void DrawPage(RenderTarget& target);
|
|
void OnSize(UINT width, UINT height);
|
|
void OnScroll(UINT message, UINT request);
|
|
void GetCaretRect(OUT RectF& rect);
|
|
void UpdateSystemCaret(const RectF& rect);
|
|
void SetRenderTarget(RenderTarget* target);
|
|
void PostRedraw() { InvalidateRect(hwnd_, NULL, FALSE); }
|
|
|
|
////////////////////
|
|
// Used by the main application to respond to button commands.
|
|
void CopyToClipboard();
|
|
void DeleteSelection();
|
|
void PasteFromClipboard();
|
|
HRESULT InsertText(const wchar_t* text);
|
|
|
|
////////////////////
|
|
// Layout/editing/caret navigation
|
|
void UpdateCaretFormatting();
|
|
bool SetSelection(SetSelectionMode moveMode, UINT32 advance, bool extendSelection, bool updateCaretFormat = true);
|
|
DWRITE_TEXT_RANGE GetSelectionRange();
|
|
UINT32 GetCaretPosition();
|
|
IDWriteTextLayout* GetLayout() { return textLayout_; }
|
|
EditableLayout::CaretFormat& GetCaretFormat() { return caretFormat_; }
|
|
|
|
////////////////////
|
|
// Current view
|
|
float GetAngle() {return angle_;}
|
|
float SetAngle(float angle, bool relativeAdjustement);
|
|
void SetScale(float scaleX, float scaleY, bool relativeAdjustement);
|
|
void GetScale(OUT float* scaleX, OUT float* scaleY);
|
|
void GetViewMatrix(OUT DWRITE_MATRIX* matrix) const;
|
|
void GetInverseViewMatrix(OUT DWRITE_MATRIX* matrix) const;
|
|
void ResetView();
|
|
void RefreshView();
|
|
|
|
protected:
|
|
HRESULT Initialize(HWND parentHwnd, const wchar_t* text, IDWriteTextFormat* textFormat);
|
|
void InitDefaults();
|
|
void InitViewDefaults();
|
|
|
|
bool SetSelectionFromPoint(float x, float y, bool extendSelection);
|
|
void AlignCaretToNearestCluster(bool isTrailingHit = false, bool skipZeroWidth = false);
|
|
|
|
void UpdateScrollInfo();
|
|
void ConstrainViewOrigin();
|
|
void TextWasEdited();
|
|
|
|
void GetLineMetrics(OUT std::vector<DWRITE_LINE_METRICS>& lineMetrics);
|
|
void GetLineFromPosition(
|
|
const DWRITE_LINE_METRICS* lineMetrics, // [lineCount]
|
|
UINT32 lineCount,
|
|
UINT32 textPosition,
|
|
OUT UINT32* lineOut,
|
|
OUT UINT32* linePositionOut
|
|
);
|
|
|
|
protected:
|
|
HWND hwnd_;
|
|
|
|
RenderTarget* renderTarget_;
|
|
DrawingEffect* pageBackgroundEffect_;
|
|
DrawingEffect* textSelectionEffect_;
|
|
DrawingEffect* imageSelectionEffect_;
|
|
DrawingEffect* caretBackgroundEffect_;
|
|
IDWriteTextLayout* textLayout_;
|
|
EditableLayout layoutEditor_;
|
|
|
|
std::wstring text_;
|
|
|
|
////////////////////
|
|
// Selection/Caret navigation
|
|
///
|
|
// caretAnchor equals caretPosition when there is no selection.
|
|
// Otherwise, the anchor holds the point where shift was held
|
|
// or left drag started.
|
|
//
|
|
// The offset is used as a sort of trailing edge offset from
|
|
// the caret position. For example, placing the caret on the
|
|
// trailing side of a surrogate pair at the beginning of the
|
|
// text would place the position at zero and offset of two.
|
|
// So to get the absolute leading position, sum the two.
|
|
UINT32 caretAnchor_;
|
|
UINT32 caretPosition_;
|
|
UINT32 caretPositionOffset_; // > 0 used for trailing edge
|
|
|
|
// Current attributes of the caret, which can be independent
|
|
// of the text.
|
|
EditableLayout::CaretFormat caretFormat_;
|
|
|
|
////////////////////
|
|
// Mouse manipulation
|
|
bool currentlySelecting_ : 1;
|
|
bool currentlyPanning_ : 1;
|
|
float previousMouseX;
|
|
float previousMouseY;
|
|
|
|
enum {MouseScrollFactor = 10};
|
|
|
|
////////////////////
|
|
// Current view
|
|
float scaleX_; // horizontal scaling
|
|
float scaleY_; // vertical scaling
|
|
float angle_; // in degrees
|
|
float originX_; // focused point in document (moves on panning and caret navigation)
|
|
float originY_;
|
|
float contentWidth_; // page size - margin left - margin right (can be fixed or variable)
|
|
float contentHeight_;
|
|
};
|