mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Switched ConsoleDlg over to richtext
This commit is contained in:
@@ -2,26 +2,9 @@
|
||||
===========================================================================
|
||||
|
||||
IceTech GPL Source Code
|
||||
Copyright (C) 2026 Justin Marshall
|
||||
Copyright (C) 2026 Justin Marshall
|
||||
|
||||
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
||||
|
||||
IceTech Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
IceTech Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
||||
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
@@ -37,52 +20,441 @@ If you have questions concerning this license or the applicable additional terms
|
||||
// CConsoleDlg dialog
|
||||
|
||||
IMPLEMENT_DYNCREATE(CConsoleDlg, CDialog)
|
||||
|
||||
CConsoleDlg::CConsoleDlg(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(CConsoleDlg::IDD)
|
||||
: CDialog(CConsoleDlg::IDD, pParent)
|
||||
{
|
||||
currentHistoryPosition = -1;
|
||||
currentCommand = "";
|
||||
currentHistoryPosition = -1;
|
||||
currentCommand = "";
|
||||
saveCurrentCommand = true;
|
||||
}
|
||||
|
||||
CConsoleDlg::~CConsoleDlg()
|
||||
{
|
||||
if (blackBrush.GetSafeHandle() != NULL) {
|
||||
blackBrush.DeleteObject();
|
||||
}
|
||||
}
|
||||
|
||||
void CConsoleDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
DDX_Control(pDX, IDC_EDIT_CONSOLE, editConsole);
|
||||
|
||||
// Do not DDX IDC_EDIT_CONSOLE here.
|
||||
// The resource control can stay as a normal EDIT placeholder.
|
||||
// OnInitDialog destroys it and creates the RichEdit in its place.
|
||||
DDX_Control(pDX, IDC_EDIT_INPUT, editInput);
|
||||
}
|
||||
|
||||
void CConsoleDlg::AddText( const char *msg ) {
|
||||
idStr work;
|
||||
CString work2;
|
||||
|
||||
work = msg;
|
||||
work.RemoveColors();
|
||||
work = CEntityDlg::TranslateString( work.c_str() );
|
||||
editConsole.GetWindowText( work2 );
|
||||
int len = work2.GetLength();
|
||||
if ( len + work.Length() > (int)editConsole.GetLimitText() ) {
|
||||
work2 = work2.Right( editConsole.GetLimitText() * 0.75 );
|
||||
len = work2.GetLength();
|
||||
editConsole.SetWindowText(work2);
|
||||
}
|
||||
editConsole.SetSel( len, len );
|
||||
editConsole.ReplaceSel( work );
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CConsoleDlg, CDialog)
|
||||
ON_WM_SIZE()
|
||||
ON_WM_SETFOCUS()
|
||||
ON_WM_ACTIVATE()
|
||||
ON_WM_CTLCOLOR()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
// CConsoleDlg message handlers
|
||||
BOOL CConsoleDlg::OnInitDialog()
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
// Needed before creating CRichEditCtrl.
|
||||
// Safe if already initialized elsewhere.
|
||||
AfxInitRichEdit2();
|
||||
|
||||
if (blackBrush.GetSafeHandle() == NULL) {
|
||||
blackBrush.CreateSolidBrush(RGB(0, 0, 0));
|
||||
}
|
||||
|
||||
CreateRichConsoleFromPlaceholder();
|
||||
SetupRichConsoleDefaults();
|
||||
|
||||
if (editInput.GetSafeHwnd() != NULL) {
|
||||
editInput.SetLimitText(1024);
|
||||
editInput.SetWindowText("");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CConsoleDlg::CreateRichConsoleFromPlaceholder()
|
||||
{
|
||||
CWnd* oldConsole = GetDlgItem(IDC_EDIT_CONSOLE);
|
||||
if (oldConsole == NULL || oldConsole->GetSafeHwnd() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
CRect rc;
|
||||
oldConsole->GetWindowRect(&rc);
|
||||
ScreenToClient(&rc);
|
||||
|
||||
oldConsole->DestroyWindow();
|
||||
|
||||
DWORD style =
|
||||
WS_CHILD |
|
||||
WS_VISIBLE |
|
||||
WS_TABSTOP |
|
||||
WS_VSCROLL |
|
||||
ES_MULTILINE |
|
||||
ES_AUTOVSCROLL |
|
||||
ES_READONLY |
|
||||
ES_NOHIDESEL |
|
||||
ES_SAVESEL;
|
||||
|
||||
// Older MFC CRichEditCtrl::Create only takes 4 args.
|
||||
// Do not use CreateEx here.
|
||||
editConsole.Create(
|
||||
style,
|
||||
rc,
|
||||
this,
|
||||
IDC_EDIT_CONSOLE
|
||||
);
|
||||
}
|
||||
|
||||
void CConsoleDlg::SetupRichConsoleDefaults()
|
||||
{
|
||||
if (editConsole.GetSafeHwnd() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
editConsole.SetEventMask(0);
|
||||
editConsole.SetOptions(ECOOP_OR, ECO_AUTOVSCROLL);
|
||||
editConsole.SetReadOnly(TRUE);
|
||||
|
||||
// CRichEditCtrl uses LimitText(), not SetLimitText().
|
||||
editConsole.LimitText(1024 * 1024);
|
||||
|
||||
editConsole.SetBackgroundColor(FALSE, RGB(0, 0, 0));
|
||||
|
||||
CHARFORMAT cf;
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
cf.cbSize = sizeof(cf);
|
||||
cf.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE;
|
||||
cf.crTextColor = ICE_CONSOLE_DEFAULT_COLOR;
|
||||
cf.yHeight = 180; // 9pt
|
||||
|
||||
lstrcpyn(cf.szFaceName, "Consolas", LF_FACESIZE);
|
||||
|
||||
editConsole.SetDefaultCharFormat(cf);
|
||||
|
||||
editConsole.SetSel(0, -1);
|
||||
editConsole.SetSelectionCharFormat(cf);
|
||||
editConsole.SetSel(-1, -1);
|
||||
}
|
||||
|
||||
CString CConsoleDlg::NormalizeNewlines(const CString& in) const
|
||||
{
|
||||
CString out;
|
||||
out.Preallocate(in.GetLength() + 16);
|
||||
|
||||
for (int i = 0; i < in.GetLength(); i++) {
|
||||
TCHAR c = in[i];
|
||||
|
||||
if (c == '\r') {
|
||||
if (i + 1 < in.GetLength() && in[i + 1] == '\n') {
|
||||
out += "\r\n";
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
out += "\r\n";
|
||||
}
|
||||
}
|
||||
else if (c == '\n') {
|
||||
out += "\r\n";
|
||||
}
|
||||
else {
|
||||
out += c;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
COLORREF CConsoleDlg::DoomColorForIndex(char c) const
|
||||
{
|
||||
switch (c) {
|
||||
case '0':
|
||||
return RGB(0, 0, 0); // black
|
||||
|
||||
case '1':
|
||||
return RGB(255, 64, 64); // red
|
||||
|
||||
case '2':
|
||||
return RGB(64, 255, 64); // green
|
||||
|
||||
case '3':
|
||||
return RGB(255, 255, 64); // yellow
|
||||
|
||||
case '4':
|
||||
return RGB(80, 140, 255); // blue
|
||||
|
||||
case '5':
|
||||
return RGB(64, 255, 255); // cyan
|
||||
|
||||
case '6':
|
||||
return RGB(255, 64, 255); // magenta
|
||||
|
||||
case '7':
|
||||
return RGB(230, 230, 230); // white
|
||||
|
||||
case '8':
|
||||
return RGB(160, 160, 160); // gray
|
||||
|
||||
case '9':
|
||||
return RGB(255, 150, 32); // orange
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
return RGB(255, 64, 64);
|
||||
|
||||
case 'g':
|
||||
case 'G':
|
||||
return RGB(64, 255, 64);
|
||||
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return RGB(255, 255, 64);
|
||||
|
||||
case 'b':
|
||||
case 'B':
|
||||
return RGB(80, 140, 255);
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
return RGB(64, 255, 255);
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
return RGB(255, 64, 255);
|
||||
|
||||
case 'w':
|
||||
case 'W':
|
||||
return RGB(230, 230, 230);
|
||||
|
||||
default:
|
||||
return ICE_CONSOLE_DEFAULT_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ConsoleStartsWithNoCase(const char* s, const char* prefix)
|
||||
{
|
||||
if (s == NULL || prefix == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (*prefix != '\0') {
|
||||
char a = *s;
|
||||
char b = *prefix;
|
||||
|
||||
if (a >= 'A' && a <= 'Z') {
|
||||
a = a - 'A' + 'a';
|
||||
}
|
||||
|
||||
if (b >= 'A' && b <= 'Z') {
|
||||
b = b - 'A' + 'a';
|
||||
}
|
||||
|
||||
if (a != b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s++;
|
||||
prefix++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
COLORREF CConsoleDlg::DoomColorForName(const char* name, int& consumed) const
|
||||
{
|
||||
consumed = 0;
|
||||
|
||||
struct colorName_t {
|
||||
const char* name;
|
||||
COLORREF color;
|
||||
};
|
||||
|
||||
static const colorName_t names[] = {
|
||||
{ "S_COLOR_BLACK", RGB(0, 0, 0) },
|
||||
{ "S_COLOR_RED", RGB(255, 64, 64) },
|
||||
{ "S_COLOR_GREEN", RGB(64, 255, 64) },
|
||||
{ "S_COLOR_YELLOW", RGB(255, 255, 64) },
|
||||
{ "S_COLOR_BLUE", RGB(80, 140, 255) },
|
||||
{ "S_COLOR_CYAN", RGB(64, 255, 255) },
|
||||
{ "S_COLOR_MAGENTA", RGB(255, 64, 255) },
|
||||
{ "S_COLOR_WHITE", RGB(230, 230, 230) },
|
||||
{ "S_COLOR_GRAY", RGB(160, 160, 160) },
|
||||
{ "S_COLOR_GREY", RGB(160, 160, 160) },
|
||||
{ "S_COLOR_ORANGE", RGB(255, 150, 32) },
|
||||
|
||||
{ "COLOR_BLACK", RGB(0, 0, 0) },
|
||||
{ "COLOR_RED", RGB(255, 64, 64) },
|
||||
{ "COLOR_GREEN", RGB(64, 255, 64) },
|
||||
{ "COLOR_YELLOW", RGB(255, 255, 64) },
|
||||
{ "COLOR_BLUE", RGB(80, 140, 255) },
|
||||
{ "COLOR_CYAN", RGB(64, 255, 255) },
|
||||
{ "COLOR_MAGENTA", RGB(255, 64, 255) },
|
||||
{ "COLOR_WHITE", RGB(230, 230, 230) },
|
||||
{ "COLOR_GRAY", RGB(160, 160, 160) },
|
||||
{ "COLOR_GREY", RGB(160, 160, 160) },
|
||||
{ "COLOR_ORANGE", RGB(255, 150, 32) }
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
|
||||
if (ConsoleStartsWithNoCase(name, names[i].name)) {
|
||||
consumed = (int)strlen(names[i].name);
|
||||
return names[i].color;
|
||||
}
|
||||
}
|
||||
|
||||
return ICE_CONSOLE_DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
bool CConsoleDlg::TryConsumeColorToken(const char* s, int& consumed, COLORREF& color) const
|
||||
{
|
||||
consumed = 0;
|
||||
color = ICE_CONSOLE_DEFAULT_COLOR;
|
||||
|
||||
if (s == NULL || s[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Doom/idTech style color escape: ^1, ^2, ^7, etc.
|
||||
if (s[0] == '^' && s[1] != '\0') {
|
||||
// ^^ means literal caret, not a color.
|
||||
if (s[1] == '^') {
|
||||
return false;
|
||||
}
|
||||
|
||||
color = DoomColorForIndex(s[1]);
|
||||
consumed = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Optional support if some code emits literal token names.
|
||||
int namedConsumed = 0;
|
||||
COLORREF namedColor = DoomColorForName(s, namedConsumed);
|
||||
if (namedConsumed > 0) {
|
||||
color = namedColor;
|
||||
consumed = namedConsumed;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CConsoleDlg::AppendConsoleRun(const CString& text, COLORREF color)
|
||||
{
|
||||
if (text.IsEmpty() || editConsole.GetSafeHwnd() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
CString normalized = NormalizeNewlines(text);
|
||||
|
||||
editConsole.SetReadOnly(FALSE);
|
||||
|
||||
int len = editConsole.GetTextLength();
|
||||
editConsole.SetSel(len, len);
|
||||
|
||||
CHARFORMAT cf;
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
cf.cbSize = sizeof(cf);
|
||||
cf.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE;
|
||||
cf.crTextColor = color;
|
||||
cf.yHeight = 180;
|
||||
lstrcpyn(cf.szFaceName, "Consolas", LF_FACESIZE);
|
||||
|
||||
editConsole.SetSelectionCharFormat(cf);
|
||||
editConsole.ReplaceSel(normalized, FALSE);
|
||||
|
||||
editConsole.SetReadOnly(TRUE);
|
||||
}
|
||||
|
||||
void CConsoleDlg::TrimConsoleIfNeeded()
|
||||
{
|
||||
if (editConsole.GetSafeHwnd() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int maxChars = 512 * 1024;
|
||||
const int trimToChars = 384 * 1024;
|
||||
|
||||
int len = editConsole.GetTextLength();
|
||||
if (len <= maxChars) {
|
||||
return;
|
||||
}
|
||||
|
||||
int removeCount = len - trimToChars;
|
||||
|
||||
editConsole.SetReadOnly(FALSE);
|
||||
editConsole.SetSel(0, removeCount);
|
||||
editConsole.ReplaceSel("", FALSE);
|
||||
editConsole.SetReadOnly(TRUE);
|
||||
}
|
||||
|
||||
void CConsoleDlg::AppendConsoleTextColored(const char* text)
|
||||
{
|
||||
if (text == NULL || editConsole.GetSafeHwnd() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
COLORREF currentColor = ICE_CONSOLE_DEFAULT_COLOR;
|
||||
CString run;
|
||||
|
||||
const char* p = text;
|
||||
|
||||
while (*p != '\0') {
|
||||
int consumed = 0;
|
||||
COLORREF newColor = ICE_CONSOLE_DEFAULT_COLOR;
|
||||
|
||||
if (TryConsumeColorToken(p, consumed, newColor)) {
|
||||
if (!run.IsEmpty()) {
|
||||
AppendConsoleRun(run, currentColor);
|
||||
run.Empty();
|
||||
}
|
||||
|
||||
currentColor = newColor;
|
||||
p += consumed;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p[0] == '^' && p[1] == '^') {
|
||||
run += '^';
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
run += *p;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (!run.IsEmpty()) {
|
||||
AppendConsoleRun(run, currentColor);
|
||||
}
|
||||
|
||||
TrimConsoleIfNeeded();
|
||||
|
||||
int len = editConsole.GetTextLength();
|
||||
editConsole.SetSel(len, len);
|
||||
editConsole.SendMessage(EM_SCROLLCARET, 0, 0);
|
||||
}
|
||||
|
||||
void CConsoleDlg::AddText(const char* msg)
|
||||
{
|
||||
if (msg == NULL || editConsole.GetSafeHwnd() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
idStr work;
|
||||
|
||||
work = msg;
|
||||
|
||||
// DO NOT call RemoveColors() here.
|
||||
// The RichEdit append path consumes Doom color codes and applies colors.
|
||||
work = CEntityDlg::TranslateString(work.c_str());
|
||||
|
||||
AppendConsoleTextColored(work.c_str());
|
||||
}
|
||||
|
||||
void CConsoleDlg::OnSize(UINT nType, int cx, int cy)
|
||||
{
|
||||
@@ -92,158 +464,212 @@ void CConsoleDlg::OnSize(UINT nType, int cx, int cy)
|
||||
return;
|
||||
}
|
||||
|
||||
CRect rect, crect;
|
||||
GetWindowRect(rect);
|
||||
editInput.GetWindowRect(crect);
|
||||
CRect clientRect;
|
||||
GetClientRect(&clientRect);
|
||||
|
||||
editInput.SetWindowPos(NULL, 4, rect.Height() - 4 - crect.Height(), rect.Width() - 8, crect.Height(), SWP_SHOWWINDOW);
|
||||
editConsole.SetWindowPos(NULL, 4, 4, rect.Width() - 8, rect.Height() - crect.Height() - 8, SWP_SHOWWINDOW);
|
||||
CRect inputRect;
|
||||
editInput.GetWindowRect(&inputRect);
|
||||
|
||||
const int margin = 4;
|
||||
const int inputHeight = inputRect.Height();
|
||||
|
||||
editInput.SetWindowPos(
|
||||
NULL,
|
||||
margin,
|
||||
clientRect.Height() - margin - inputHeight,
|
||||
clientRect.Width() - margin * 2,
|
||||
inputHeight,
|
||||
SWP_SHOWWINDOW
|
||||
);
|
||||
|
||||
if (editConsole.GetSafeHwnd() != NULL) {
|
||||
editConsole.SetWindowPos(
|
||||
NULL,
|
||||
margin,
|
||||
margin,
|
||||
clientRect.Width() - margin * 2,
|
||||
clientRect.Height() - inputHeight - margin * 3,
|
||||
SWP_SHOWWINDOW
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CConsoleDlg::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
|
||||
if (pMsg->hwnd == editInput.GetSafeHwnd()) {
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE ) {
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) {
|
||||
Select_Deselect();
|
||||
g_pParentWnd->SetFocus ();
|
||||
g_pParentWnd->SetFocus();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) {
|
||||
ExecuteCommand();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE ) {
|
||||
if (pMsg->wParam == VK_ESCAPE) {
|
||||
g_pParentWnd->GetCamera()->SetFocus();
|
||||
Select_Deselect();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_UP ) {
|
||||
//save off the current in-progress command so we can get back to it
|
||||
if ( saveCurrentCommand == true ) {
|
||||
CString str;
|
||||
editInput.GetWindowText ( str );
|
||||
currentCommand = str.GetBuffer ( 0 );
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_UP) {
|
||||
// Save off the current in-progress command so we can get back to it.
|
||||
if (saveCurrentCommand == true) {
|
||||
CString str;
|
||||
editInput.GetWindowText(str);
|
||||
currentCommand = str.GetBuffer(0);
|
||||
saveCurrentCommand = false;
|
||||
}
|
||||
|
||||
if ( consoleHistory.Num () > 0 ) {
|
||||
editInput.SetWindowText ( consoleHistory[currentHistoryPosition] );
|
||||
|
||||
int selLocation = consoleHistory[currentHistoryPosition].Length ();
|
||||
editInput.SetSel ( selLocation , selLocation + 1);
|
||||
}
|
||||
|
||||
if ( currentHistoryPosition > 0) {
|
||||
--currentHistoryPosition;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DOWN ) {
|
||||
int selLocation = 0;
|
||||
if ( currentHistoryPosition < consoleHistory.Num () - 1 ) {
|
||||
++currentHistoryPosition;
|
||||
editInput.SetWindowText ( consoleHistory[currentHistoryPosition] );
|
||||
selLocation = consoleHistory[currentHistoryPosition].Length ();
|
||||
}
|
||||
else {
|
||||
editInput.SetWindowText ( currentCommand );
|
||||
selLocation = currentCommand.Length ();
|
||||
currentCommand.Clear ();
|
||||
saveCurrentCommand = true;
|
||||
}
|
||||
|
||||
editInput.SetSel ( selLocation , selLocation + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB ) {
|
||||
common->Printf ( "Command History\n----------------\n" );
|
||||
for ( int i = 0 ; i < consoleHistory.Num ();i++ )
|
||||
{
|
||||
common->Printf ( "[cmd %d]: %s\n" , i , consoleHistory[i].c_str() );
|
||||
}
|
||||
common->Printf ( "----------------\n" );
|
||||
}
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_NEXT) {
|
||||
editConsole.LineScroll ( 10 );
|
||||
|
||||
if (consoleHistory.Num() > 0) {
|
||||
if (currentHistoryPosition < 0) {
|
||||
currentHistoryPosition = consoleHistory.Num() - 1;
|
||||
}
|
||||
if (currentHistoryPosition >= consoleHistory.Num()) {
|
||||
currentHistoryPosition = consoleHistory.Num() - 1;
|
||||
}
|
||||
|
||||
editInput.SetWindowText(consoleHistory[currentHistoryPosition]);
|
||||
|
||||
int selLocation = consoleHistory[currentHistoryPosition].Length();
|
||||
editInput.SetSel(selLocation, selLocation);
|
||||
|
||||
if (currentHistoryPosition > 0) {
|
||||
--currentHistoryPosition;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_PRIOR ) {
|
||||
editConsole.LineScroll ( -10 );
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DOWN) {
|
||||
int selLocation = 0;
|
||||
|
||||
if (currentHistoryPosition < consoleHistory.Num() - 1) {
|
||||
++currentHistoryPosition;
|
||||
editInput.SetWindowText(consoleHistory[currentHistoryPosition]);
|
||||
selLocation = consoleHistory[currentHistoryPosition].Length();
|
||||
}
|
||||
else {
|
||||
editInput.SetWindowText(currentCommand);
|
||||
selLocation = currentCommand.Length();
|
||||
currentCommand.Clear();
|
||||
saveCurrentCommand = true;
|
||||
}
|
||||
|
||||
editInput.SetSel(selLocation, selLocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_HOME ) {
|
||||
editConsole.LineScroll ( -editConsole.GetLineCount() );
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) {
|
||||
common->Printf("Command History\n----------------\n");
|
||||
|
||||
for (int i = 0; i < consoleHistory.Num(); i++) {
|
||||
common->Printf("[cmd %d]: %s\n", i, consoleHistory[i].c_str());
|
||||
}
|
||||
|
||||
common->Printf("----------------\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_END ) {
|
||||
editConsole.LineScroll ( editConsole.GetLineCount() );
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_NEXT) {
|
||||
if (editConsole.GetSafeHwnd() != NULL) {
|
||||
editConsole.LineScroll(10);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_PRIOR) {
|
||||
if (editConsole.GetSafeHwnd() != NULL) {
|
||||
editConsole.LineScroll(-10);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_HOME) {
|
||||
if (editConsole.GetSafeHwnd() != NULL) {
|
||||
editConsole.LineScroll(-editConsole.GetLineCount());
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_END) {
|
||||
if (editConsole.GetSafeHwnd() != NULL) {
|
||||
editConsole.LineScroll(editConsole.GetLineCount());
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return CDialog::PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
void CConsoleDlg::OnSetFocus(CWnd* pOldWnd) {
|
||||
void CConsoleDlg::OnSetFocus(CWnd* pOldWnd)
|
||||
{
|
||||
CDialog::OnSetFocus(pOldWnd);
|
||||
editInput.SetFocus();
|
||||
|
||||
if (editInput.GetSafeHwnd() != NULL) {
|
||||
editInput.SetFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void CConsoleDlg::SetConsoleText ( const idStr& text ) {
|
||||
editInput.Clear ();
|
||||
editInput.SetWindowText ( text.c_str() );
|
||||
void CConsoleDlg::SetConsoleText(const idStr& text)
|
||||
{
|
||||
if (editInput.GetSafeHwnd() != NULL) {
|
||||
editInput.Clear();
|
||||
editInput.SetWindowText(text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void CConsoleDlg::ExecuteCommand ( const idStr& cmd ) {
|
||||
void CConsoleDlg::ExecuteCommand(const idStr& cmd)
|
||||
{
|
||||
CString str;
|
||||
if ( cmd.Length() > 0 ) {
|
||||
|
||||
if (cmd.Length() > 0) {
|
||||
str = cmd;
|
||||
}
|
||||
else {
|
||||
editInput.GetWindowText(str);
|
||||
}
|
||||
|
||||
if ( str != "" ) {
|
||||
if (str != "") {
|
||||
editInput.SetWindowText("");
|
||||
common->Printf("%s\n", str.GetBuffer(0));
|
||||
|
||||
//avoid adding multiple identical commands in a row
|
||||
int index = consoleHistory.Num ();
|
||||
common->Printf("%s\n", str.GetBuffer(0));
|
||||
|
||||
if ( index == 0 || str.GetBuffer(0) != consoleHistory[index-1]) {
|
||||
//keep the history to 16 commands, removing the oldest command
|
||||
if ( consoleHistory.Num () > 16 ) {
|
||||
consoleHistory.RemoveIndex ( 0 );
|
||||
// Avoid adding multiple identical commands in a row.
|
||||
int index = consoleHistory.Num();
|
||||
|
||||
if (index == 0 || str.GetBuffer(0) != consoleHistory[index - 1]) {
|
||||
// Keep the history to 16 commands, removing the oldest command.
|
||||
if (consoleHistory.Num() > 16) {
|
||||
consoleHistory.RemoveIndex(0);
|
||||
}
|
||||
currentHistoryPosition = consoleHistory.Append ( str.GetBuffer (0) );
|
||||
|
||||
currentHistoryPosition = consoleHistory.Append(str.GetBuffer(0));
|
||||
}
|
||||
else {
|
||||
currentHistoryPosition = consoleHistory.Num () - 1;
|
||||
currentHistoryPosition = consoleHistory.Num() - 1;
|
||||
}
|
||||
|
||||
currentCommand.Clear ();
|
||||
currentCommand.Clear();
|
||||
saveCurrentCommand = true;
|
||||
|
||||
bool propogateCommand = true;
|
||||
|
||||
//process some of our own special commands
|
||||
if ( str.CompareNoCase ( "clear" ) == 0) {
|
||||
editConsole.SetSel ( 0 , -1 );
|
||||
editConsole.Clear ();
|
||||
}
|
||||
else if ( str.CompareNoCase ( "edit" ) == 0) {
|
||||
// Process some of our own special commands.
|
||||
if (str.CompareNoCase("clear") == 0) {
|
||||
if (editConsole.GetSafeHwnd() != NULL) {
|
||||
editConsole.SetReadOnly(FALSE);
|
||||
editConsole.SetSel(0, -1);
|
||||
editConsole.ReplaceSel("", FALSE);
|
||||
editConsole.SetReadOnly(TRUE);
|
||||
}
|
||||
|
||||
propogateCommand = false;
|
||||
}
|
||||
if ( propogateCommand ) {
|
||||
cmdSystem->BufferCommandText( CMD_EXEC_NOW, str );
|
||||
else if (str.CompareNoCase("edit") == 0) {
|
||||
propogateCommand = false;
|
||||
}
|
||||
|
||||
if (propogateCommand) {
|
||||
cmdSystem->BufferCommandText(CMD_EXEC_NOW, str);
|
||||
}
|
||||
|
||||
Sys_UpdateWindows(W_ALL);
|
||||
@@ -254,8 +680,22 @@ void CConsoleDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
|
||||
{
|
||||
CDialog::OnActivate(nState, pWndOther, bMinimized);
|
||||
|
||||
if ( nState == WA_ACTIVE || nState == WA_CLICKACTIVE )
|
||||
{
|
||||
editInput.SetFocus();
|
||||
}
|
||||
if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) {
|
||||
if (editInput.GetSafeHwnd() != NULL) {
|
||||
editInput.SetFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HBRUSH CConsoleDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
|
||||
{
|
||||
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
|
||||
|
||||
if (pWnd != NULL && pWnd->GetSafeHwnd() == editInput.GetSafeHwnd()) {
|
||||
pDC->SetBkColor(RGB(0, 0, 0));
|
||||
pDC->SetTextColor(ICE_CONSOLE_DEFAULT_COLOR);
|
||||
return (HBRUSH)blackBrush.GetSafeHandle();
|
||||
}
|
||||
|
||||
return hbr;
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
===========================================================================
|
||||
|
||||
IceTech GPL Source Code
|
||||
Copyright (C) 2026 Justin Marshall
|
||||
Copyright (C) 2026 Justin Marshall
|
||||
|
||||
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
||||
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
||||
|
||||
IceTech Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,17 +16,15 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "afxwin.h"
|
||||
#include "afxrich.h"
|
||||
|
||||
|
||||
#define ICE_CONSOLE_DEFAULT_COLOR RGB(64, 255, 255)
|
||||
|
||||
|
||||
// CConsoleDlg dialog
|
||||
@@ -36,31 +34,50 @@ class CConsoleDlg : public CDialog
|
||||
DECLARE_DYNCREATE(CConsoleDlg)
|
||||
|
||||
public:
|
||||
CConsoleDlg(CWnd* pParent = NULL); // standard constructor
|
||||
CConsoleDlg(CWnd* pParent = NULL);
|
||||
virtual ~CConsoleDlg();
|
||||
|
||||
// Dialog Data
|
||||
enum { IDD = IDD_DIALOG_CONSOLE };
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
virtual void DoDataExchange(CDataExchange* pDX);
|
||||
virtual BOOL OnInitDialog();
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
CEdit editConsole;
|
||||
CRichEditCtrl editConsole;
|
||||
CEdit editInput;
|
||||
void AddText(const char *msg);
|
||||
void SetConsoleText ( const idStr& text );
|
||||
void ExecuteCommand ( const idStr& cmd = "" );
|
||||
|
||||
|
||||
void AddText(const char* msg);
|
||||
void SetConsoleText(const idStr& text);
|
||||
void ExecuteCommand(const idStr& cmd = "");
|
||||
|
||||
idStr consoleStr;
|
||||
idStrList consoleHistory;
|
||||
idStr currentCommand;
|
||||
int currentHistoryPosition;
|
||||
idStrList consoleHistory;
|
||||
idStr currentCommand;
|
||||
int currentHistoryPosition;
|
||||
bool saveCurrentCommand;
|
||||
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||||
afx_msg void OnSetFocus(CWnd* pOldWnd);
|
||||
afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
|
||||
};
|
||||
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
|
||||
|
||||
private:
|
||||
CBrush blackBrush;
|
||||
|
||||
void CreateRichConsoleFromPlaceholder();
|
||||
void SetupRichConsoleDefaults();
|
||||
|
||||
void AppendConsoleTextColored(const char* text);
|
||||
void AppendConsoleRun(const CString& text, COLORREF color);
|
||||
void TrimConsoleIfNeeded();
|
||||
|
||||
bool TryConsumeColorToken(const char* s, int& consumed, COLORREF& color) const;
|
||||
COLORREF DoomColorForIndex(char c) const;
|
||||
COLORREF DoomColorForName(const char* name, int& consumed) const;
|
||||
|
||||
CString NormalizeNewlines(const CString& in) const;
|
||||
};
|
||||
Reference in New Issue
Block a user