#include "guiterm.h"
+/* GLOBALS ********************************************************************/
+
+#define IS_WHITESPACE(c) ((c) == L'\0' || (c) == L' ' || (c) == L'\t')
+
/* FUNCTIONS ******************************************************************/
-COLORREF PaletteRGBFromAttrib(PCONSOLE Console, WORD Attribute)
+static COLORREF
+PaletteRGBFromAttrib(PCONSOLE Console, WORD Attribute)
{
HPALETTE hPalette = Console->ActiveBuffer->PaletteHandle;
PALETTEENTRY pe;
return PALETTERGB(pe.peRed, pe.peGreen, pe.peBlue);
}
-VOID
-GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
- PGUI_CONSOLE_DATA GuiData)
+static HFONT
+ChangeFontAttributes(PGUI_CONSOLE_DATA GuiData,
+ // COORD FontSize,
+ ULONG FontWeight,
+ BOOLEAN bItalic,
+ BOOLEAN bUnderline,
+ BOOLEAN bStrikeOut)
{
- /*
- * This function supposes that the system clipboard was opened.
- */
+ HFONT NewFont;
+ LOGFONT lf;
+
+ /* Initialize the LOGFONT structure */
+ RtlZeroMemory(&lf, sizeof(lf));
+
+ /* Retrieve the details of the current font */
+ if (GetObject(GuiData->Font, sizeof(lf), &lf) == 0)
+ return NULL; // GuiData->Font;
+
+ /* Change the font attributes */
+ // lf.lfHeight = FontSize.Y;
+ // lf.lfWidth = FontSize.X;
+ lf.lfWeight = FontWeight;
+ lf.lfItalic = bItalic;
+ lf.lfUnderline = bUnderline;
+ lf.lfStrikeOut = bStrikeOut;
+
+ /* Build a new font */
+ NewFont = CreateFontIndirect(&lf);
+ if (NewFont == NULL)
+ return NULL; // GuiData->Font;
+
+ // FIXME: Do we need to update GuiData->CharWidth and GuiData->CharHeight ??
+
+ /* Select it (return the old font) */
+ // return SelectObject(GuiData->hMemDC, NewFont);
+ return NewFont;
+}
+static VOID
+CopyBlock(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PSMALL_RECT Selection)
+{
/*
* Pressing the Shift key while copying text, allows us to copy
* text without newline characters (inline-text copy mode).
*/
- BOOL InlineCopyMode = (GetKeyState(VK_SHIFT) & 0x8000);
+ BOOL InlineCopyMode = !!(GetKeyState(VK_SHIFT) & 0x8000);
HANDLE hData;
PCHAR_INFO ptr;
LPWSTR data, dstPos;
ULONG selWidth, selHeight;
- ULONG xPos, yPos, size;
+ ULONG xPos, yPos;
+ ULONG size;
- selWidth = GuiData->Selection.srSelection.Right - GuiData->Selection.srSelection.Left + 1;
- selHeight = GuiData->Selection.srSelection.Bottom - GuiData->Selection.srSelection.Top + 1;
- DPRINT("Selection is (%d|%d) to (%d|%d)\n",
- GuiData->Selection.srSelection.Left,
- GuiData->Selection.srSelection.Top,
- GuiData->Selection.srSelection.Right,
- GuiData->Selection.srSelection.Bottom);
+ DPRINT("CopyBlock(%u, %u, %u, %u)\n",
+ Selection->Left, Selection->Top, Selection->Right, Selection->Bottom);
-#ifdef IS_WHITESPACE
-#undef IS_WHITESPACE
-#endif
-#define IS_WHITESPACE(c) ((c) == L'\0' || (c) == L' ' || (c) == L'\t')
+ /* Prevent against empty blocks */
+ if (Selection == NULL) return;
+ if (Selection->Left > Selection->Right || Selection->Top > Selection->Bottom)
+ return;
+
+ selWidth = Selection->Right - Selection->Left + 1;
+ selHeight = Selection->Bottom - Selection->Top + 1;
/* Basic size for one line... */
size = selWidth;
*/
size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1);
}
+ else
+ {
+ DPRINT1("This case must never happen, because selHeight is at least == 1\n");
+ }
+
size += 1; /* Null-termination */
size *= sizeof(WCHAR);
ULONG length = selWidth;
ptr = ConioCoordToPointer(Buffer,
- GuiData->Selection.srSelection.Left,
- GuiData->Selection.srSelection.Top + yPos);
+ Selection->Left,
+ Selection->Top + yPos);
/* Trim whitespace from the right */
while (length > 0)
* Sometimes, applications can put NULL chars into the screen-buffer
* (this behaviour is allowed). Detect this and replace by a space.
*/
- dstPos[xPos] = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
+ *dstPos++ = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
}
- dstPos += length;
/* Add newline characters if we are not in inline-text copy mode */
if (!InlineCopyMode)
{
if (yPos != (selHeight - 1))
{
- wcscat(data, L"\r\n");
+ wcscat(dstPos, L"\r\n");
dstPos += 2;
}
}
SetClipboardData(CF_UNICODETEXT, hData);
}
+static VOID
+CopyLines(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PCOORD Begin,
+ PCOORD End)
+{
+ HANDLE hData;
+ PCHAR_INFO ptr;
+ LPWSTR data, dstPos;
+ ULONG NumChars, size;
+ ULONG xPos, yPos, xBeg, xEnd;
+
+ DPRINT("CopyLines((%u, %u) ; (%u, %u))\n",
+ Begin->X, Begin->Y, End->X, End->Y);
+
+ /* Prevent against empty blocks... */
+ if (Begin == NULL || End == NULL) return;
+ /* ... or malformed blocks */
+ if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X)) return;
+
+ /* Compute the number of characters to copy */
+ if (End->Y == Begin->Y) // top == bottom
+ {
+ NumChars = End->X - Begin->X + 1;
+ }
+ else // if (End->Y > Begin->Y)
+ {
+ NumChars = Buffer->ScreenBufferSize.X - Begin->X;
+
+ if (End->Y >= Begin->Y + 2)
+ {
+ NumChars += (End->Y - Begin->Y - 1) * Buffer->ScreenBufferSize.X;
+ }
+
+ NumChars += End->X + 1;
+ }
+
+ size = (NumChars + 1) * sizeof(WCHAR); /* Null-terminated */
+
+ /* Allocate some memory area to be given to the clipboard, so it will not be freed here */
+ hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
+ if (hData == NULL) return;
+
+ data = GlobalLock(hData);
+ if (data == NULL)
+ {
+ GlobalFree(hData);
+ return;
+ }
+
+ DPRINT("Copying %d characters\n", NumChars);
+ dstPos = data;
+
+ /*
+ * We need to walk per-lines, and not just looping in the big screen-buffer
+ * array, because of the way things are stored inside it. The downside is
+ * that it makes the code more complicated.
+ */
+ for (yPos = Begin->Y; (yPos <= End->Y) && (NumChars > 0); yPos++)
+ {
+ xBeg = (yPos == Begin->Y ? Begin->X : 0);
+ xEnd = (yPos == End->Y ? End->X : Buffer->ScreenBufferSize.X - 1);
+
+ ptr = ConioCoordToPointer(Buffer, 0, yPos);
+
+ /* Copy only the characters, leave attributes alone */
+ for (xPos = xBeg; (xPos <= xEnd) && (NumChars-- > 0); xPos++)
+ {
+ /*
+ * Sometimes, applications can put NULL chars into the screen-buffer
+ * (this behaviour is allowed). Detect this and replace by a space.
+ */
+ *dstPos++ = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
+ }
+ }
+
+ DPRINT("Setting data <%S> to clipboard\n", data);
+ GlobalUnlock(hData);
+
+ EmptyClipboard();
+ SetClipboardData(CF_UNICODETEXT, hData);
+}
+
+
+VOID
+GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
+ PCOORD SelectionAnchor,
+ PSMALL_RECT SmallRect);
+
+VOID
+GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
+ PGUI_CONSOLE_DATA GuiData)
+{
+ /*
+ * This function supposes that the system clipboard was opened.
+ */
+
+ BOOL LineSelection = GuiData->LineSelection;
+
+ DPRINT("Selection is (%d|%d) to (%d|%d) in %s mode\n",
+ GuiData->Selection.srSelection.Left,
+ GuiData->Selection.srSelection.Top,
+ GuiData->Selection.srSelection.Right,
+ GuiData->Selection.srSelection.Bottom,
+ (LineSelection ? "line" : "block"));
+
+ if (!LineSelection)
+ {
+ CopyBlock(Buffer, &GuiData->Selection.srSelection);
+ }
+ else
+ {
+ COORD Begin, End;
+
+ GetSelectionBeginEnd(&Begin, &End,
+ &GuiData->Selection.dwSelectionAnchor,
+ &GuiData->Selection.srSelection);
+
+ CopyLines(Buffer, &Begin, &End);
+ }
+}
+
VOID
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
PGUI_CONSOLE_DATA GuiData)
WORD LastAttribute, Attribute;
ULONG CursorX, CursorY, CursorHeight;
HBRUSH CursorBrush, OldBrush;
- HFONT OldFont;
+ HFONT OldFont, NewFont;
+ BOOLEAN IsUnderscore;
if (Buffer->Buffer == NULL) return;
SetTextColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute)));
SetBkColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute)));
- OldFont = SelectObject(GuiData->hMemDC, GuiData->Font);
+ // OldFont = ChangeFontAttributes(GuiData, /* {0}, */ GuiData->GuiInfo.FontWeight, FALSE, FALSE, FALSE);
+ IsUnderscore = !!(LastAttribute & COMMON_LVB_UNDERSCORE);
+ NewFont = ChangeFontAttributes(GuiData, /* {0}, */ GuiData->GuiInfo.FontWeight,
+ FALSE,
+ IsUnderscore,
+ FALSE);
+ if (NewFont == NULL)
+ {
+ DPRINT1("ChangeFontAttributes failed, use the original font\n");
+ NewFont = GuiData->Font;
+ }
+ OldFont = SelectObject(GuiData->hMemDC, NewFont);
for (Line = TopLine; Line <= BottomLine; Line++)
{
Attribute = From->Attributes;
if (Attribute != LastAttribute)
{
- SetTextColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, TextAttribFromAttrib(Attribute)));
- SetBkColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, BkgdAttribFromAttrib(Attribute)));
LastAttribute = Attribute;
+ SetTextColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute)));
+ SetBkColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute)));
+
+ /* Change underscore state if needed */
+ if (!!(LastAttribute & COMMON_LVB_UNDERSCORE) != IsUnderscore)
+ {
+ IsUnderscore = !!(LastAttribute & COMMON_LVB_UNDERSCORE);
+
+ /* Delete the font we used up to now */
+ // SelectObject(GuiData->hMemDC, OldFont);
+ if (NewFont != GuiData->Font) DeleteObject(NewFont);
+ /* Recreate it */
+ NewFont = ChangeFontAttributes(GuiData, /* {0}, */ GuiData->GuiInfo.FontWeight,
+ FALSE,
+ IsUnderscore,
+ FALSE);
+ if (NewFont == NULL)
+ {
+ DPRINT1("ChangeFontAttributes failed, use the original font\n");
+ NewFont = GuiData->Font;
+ }
+ /* Select it */
+ /* OldFont = */ SelectObject(GuiData->hMemDC, NewFont);
+ }
}
}
GuiData->CharWidth,
CursorHeight,
PATCOPY);
+
SelectObject(GuiData->hMemDC, OldBrush);
DeleteObject(CursorBrush);
}
}
+ /* Restore the old font and delete the font we used up to now */
SelectObject(GuiData->hMemDC, OldFont);
+ if (NewFont != GuiData->Font) DeleteObject(NewFont);
LeaveCriticalSection(&Console->Lock);
}