diff --git a/code/uilib/uiconsole.cpp b/code/uilib/uiconsole.cpp index 116e150d..649e848c 100644 --- a/code/uilib/uiconsole.cpp +++ b/code/uilib/uiconsole.cpp @@ -22,14 +22,40 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "ui_local.h" +Event W_Console_ChildSizeChanged +( + "_console_childsizechanged", + EV_DEFAULT, + NULL, + NULL, + "Signal that the child area of the floating window has changed" +); + +Event EV_Console_Print +( + "print", + EV_DEFAULT, + "s", + "string", + "Print the string to the console" +); + CLASS_DECLARATION( UIWidget, UIConsole, NULL ) { + { &W_SizeChanged, &UIConsole::OnSizeChanged }, + { &EV_Console_Print, &UIConsole::Print }, { NULL, NULL } }; UIConsole::UIConsole() { + m_scroll = NULL; + m_firstitem = 0; + m_numitems = 0; + m_caret = 0; + m_scroll = new UIVertScroll(); + AllowActivate(true); } int UIConsole::getFirstItem @@ -38,8 +64,7 @@ int UIConsole::getFirstItem ) { - // FIXME: stub - return 0; + return m_firstitem; } int UIConsole::getNextItem @@ -48,8 +73,36 @@ int UIConsole::getNextItem ) { - // FIXME: stub - return 0; + if (prev == -1) { + return -1; + } + + m_numitems = m_numitems; + m_firstitem = m_firstitem; + prev = prev + 1; + + if (m_numitems < MAX_CONSOLE_ITEMS) + { + if (prev > m_firstitem) + { + if (prev - m_firstitem >= m_numitems) + return -1; + } + else if (m_firstitem + m_numitems >= prev + MAX_CONSOLE_ITEMS) + { + return -1; + } + } + + if (prev >= MAX_CONSOLE_ITEMS) { + prev = 0; + } + + if (prev != m_firstitem) { + return prev; + } + + return -1; } int UIConsole::getLastItem @@ -58,8 +111,13 @@ int UIConsole::getLastItem ) { - // FIXME: stub - return 0; + int item = m_firstitem + m_numitems; + + if (item - 1 >= MAX_CONSOLE_ITEMS) { + return item - MAX_CONSOLE_ITEMS - 1; + } + + return item - 1; } int UIConsole::AddLine @@ -68,8 +126,24 @@ int UIConsole::AddLine ) { - // FIXME: stub - return 0; + int line = getLastItem() + 1; + + if (line >= MAX_CONSOLE_ITEMS) { + line = 0; + } + + if (m_numitems <= MAX_CONSOLE_ITEMS) + { + m_numitems++; + } + else + { + m_firstitem++; + if (m_firstitem >= MAX_CONSOLE_ITEMS) { + m_firstitem = 0; + } + } + return line; } void UIConsole::DrawBottomLine @@ -78,7 +152,86 @@ void UIConsole::DrawBottomLine ) { - // FIXME: stub + int promptwidth; + static str prompt = ">"; + int top; + int iXPos; + int iMaxStringWidth; + int widthbeforecaret; + + promptwidth = m_font->getWidth(prompt.c_str(), -1); + top = m_frame.size.height - m_font->getHeight(qfalse); + m_font->Print(0.0, top, prompt.c_str(), -1, qfalse); + + iXPos = promptwidth + 1; + iMaxStringWidth = m_frame.size.width - iXPos - m_scroll->getSize().width; + + if (m_caret > m_currentline.length()) + { + // Make sure to not overflow + m_caret = m_currentline.length(); + } + + if (m_caret < 0) m_caret = 0; + + widthbeforecaret = promptwidth + m_font->getWidth(m_currentline.c_str(), m_caret); + + if (m_refreshcompletionbuffer || m_completionbuffer.length() >= m_currentline.length()) + { + static str indicator; + const char* pString; + int indicatorwidth; + int iChar; + int iCharLength; + int iStringLength; + + if (widthbeforecaret < iMaxStringWidth) + { + m_font->Print(iXPos, top, m_currentline.c_str(), -1, qfalse); + } + else + { + indicatorwidth = m_font->getWidth(indicator.c_str(), -1); + m_font->Print(iXPos, top, indicator.c_str(), -1, 0); + + iXPos += indicatorwidth; + iMaxStringWidth -= indicatorwidth; + + pString = &m_currentline[m_caret - 1]; + iStringLength = 0; + iCharLength = m_font->getCharWidth(pString[0]); + + for (iChar = m_caret; iChar > 1; --iChar) + { + iStringLength += iCharLength; + iCharLength = m_font->getCharWidth(pString[iChar - 1]); + } + + m_font->Print(iXPos, top, pString + 1, -1, qfalse); + widthbeforecaret = iXPos + m_font->getWidth(pString + 1, m_caret - iChar); + } + } + else + { + int completewidth; + int linewidth; + + completewidth = m_font->getWidth(m_completionbuffer.c_str(), -1); + linewidth = m_font->getWidth(&m_currentline[m_completionbuffer.length()], -1); + m_font->Print(iXPos, top, m_completionbuffer.c_str(), -1, qfalse); + + iXPos += completewidth; + m_font->Print(iXPos, top, &m_currentline[m_completionbuffer.length()], -1, 0); + + DrawBoxWithSolidBorder(UIRect2D(iXPos, top, linewidth, m_font->getHeight(qfalse)), UBlack, URed, 1, 2, 1.0); + } + + // + // Make the caret blink + // + if ((uid.time % 750) > 375 && IsActive()) { + DrawBox(UIRect2D(widthbeforecaret, top, 1.0, m_font->getHeight(qfalse)), m_foreground_color, 1.0); + } } void UIConsole::AddHistory @@ -96,7 +249,7 @@ void UIConsole::Print ) { - // FIXME: stub + AddText(ev->GetString(1), NULL); } void UIConsole::KeyEnter @@ -105,7 +258,19 @@ void UIConsole::KeyEnter ) { - // FIXME: stub + AddText(str(">") + m_currentline + "\n", NULL); + + if (m_consolehandler) + { + // + // call the console handler + // + m_consolehandler((m_currentline + "\n").c_str()); + } + + // clear the console input + m_currentline = ""; + m_caret = 0; } void UIConsole::setConsoleHandler @@ -114,7 +279,7 @@ void UIConsole::setConsoleHandler ) { - // FIXME: stub + m_consolehandler = handler; } void UIConsole::AddText @@ -124,7 +289,69 @@ void UIConsole::AddText ) { - // FIXME: stub + bool atbottom; + int newtop; + int i, size; + item* curitem; + + atbottom = m_scroll->getPageHeight() + m_scroll->getTopItem() >= m_scroll->getNumItems(); + newtop = m_scroll->getTopItem(); + + if (!m_numitems) + { + m_numitems = 1; + m_items[m_firstitem].string = ""; + m_items[this->m_firstitem].lines = 0; + m_items[this->m_firstitem].pColor = &m_foreground_color; + } + + curitem = &m_items[getLastItem()]; + if (!pColor) { + pColor = &m_foreground_color; + } + + for (i = 0; text[i]; i++) + { + if (text[i] == '\n') + { + curitem->pColor = pColor; + CalcLineBreaks(*curitem); + + int line = AddLine(); + curitem = &m_items[line]; + newtop -= m_items[line].lines; + m_items[line].lines = 0; + } + else + { + curitem->string += text[i]; + } + } + + curitem->pColor = pColor; + CalcLineBreaks(*curitem); + + size = 0; + for (i = m_firstitem; i != -1; i = getNextItem(i)) { + size += m_items[i].lines; + } + + m_scroll->setNumItems(size); + + if (atbottom || newtop > m_scroll->getNumItems() - m_scroll->getPageHeight()) { + m_scroll->setTopItem(m_scroll->getNumItems() - m_scroll->getPageHeight()); + } + else { + m_scroll->setTopItem(newtop); + } + + if (m_scroll->getTopItem() < 0) { + m_scroll->setTopItem(0); + } + + if (curitem->lines == 9) { + AddText("\n", NULL); + } } void UIConsole::CalcLineBreaks @@ -133,6 +360,71 @@ void UIConsole::CalcLineBreaks ) { + int i; + str sofar, checking; + int lensofar, lenchecking, len_of_space; + const char* remaining; + + lensofar = 0; + lenchecking = 0; + len_of_space = m_font->getCharWidth(' '); + remaining = theItem.string.c_str(); + + for (i = 0; remaining[i]; i++) + { + if (remaining[i] == ' ') + { + sofar += ' '; + checking = ""; + lensofar += lenchecking + len_of_space; + lenchecking = 0; + } + else + { + int charlen = m_font->getCharWidth(remaining[i]); + if (m_frame.size.width - m_scroll->getSize().width < (charlen + lenchecking + lensofar)) + { + if (lensofar) + { + lensofar = lenchecking; + theItem.breaks[theItem.lines] = sofar.length(); + sofar = checking; + lenchecking = charlen; + checking = remaining[i]; + } + else + { + theItem.breaks[theItem.lines] = checking.length(); + sofar = remaining[i]; + lenchecking = 0; + checking = ""; + } + + theItem.lines++; + + if (theItem.lines == 9) { + break; + } + } + + checking += remaining[i]; + lenchecking += charlen; + } + } + + if (remaining[i] || lenchecking || lensofar) { + theItem.breaks[theItem.lines++] = -1; + } + + lensofar = 0; + for (i = 0; i < theItem.lines; i++) + { + theItem.begins[i] = lensofar; + if (theItem.breaks[i] != -1) { + lensofar += theItem.breaks[i]; + } + } + // FIXME: stub } @@ -142,7 +434,22 @@ void UIConsole::Clear ) { - // FIXME: stub + int i; + + // clear items line + for (i = 0; i < MAX_CONSOLE_ITEMS; i++) + { + m_items[i].lines = 0; + } + + m_numitems = 0; + m_firstitem = 0; + m_caret = 0; + m_currentline = ""; + + if (m_scroll) { + m_scroll->setNumItems(0); + } } void UIConsole::FrameInitialized @@ -151,7 +458,8 @@ void UIConsole::FrameInitialized ) { - // FIXME: stub + Connect(this, W_SizeChanged, W_SizeChanged); + OnSizeChanged(NULL); } void UIConsole::Draw @@ -160,7 +468,91 @@ void UIConsole::Draw ) { - // FIXME: stub + UColor* pCurrColor; + + m_font->setColor(m_foreground_color); + pCurrColor = &m_foreground_color; + + m_scroll->setSolidBorderColor(m_background_color); + m_scroll->setBackgroundColor(m_background_color, true); + m_scroll->setBackgroundAlpha(m_alpha); + m_scroll->setForegroundColor(m_foreground_color); + + if (m_numitems) + { + int i, item; + int top; + int lines_drawn, at_line; + int topitem; + + top = (int)(m_frame.size.height - m_font->getHeight(false) * (m_scroll->getPageHeight() + 2)); + item = m_firstitem; + topitem = m_scroll->getTopItem() - 1; + + if (item == -1) { + return; + } + + i = m_items[item].lines; + while (i < topitem) { + item = getNextItem(item); + if (item == -1) { + break; + } + + i += m_items[item].lines; + } + + if (item == -1) { + // no item available + return; + } + + at_line = m_items[item].lines - (i - topitem); + lines_drawn = 0; + while (lines_drawn < m_scroll->getPageHeight() + 1) + { + if (item != -1 && at_line >= m_items[item].lines) + { + at_line = 0; + do { + item = getNextItem(item); + } + while (item != -1 && m_items[item].lines <= 0); + } + + if (at_line >= 0) + { + if (item == -1) { + break; + } + + if (at_line >= m_items[item].lines) { + break; + } + + const ::item* theItem = &m_items[item]; + if (theItem->pColor != pCurrColor) + { + m_font->setColor(*theItem->pColor); + pCurrColor = theItem->pColor; + } + + m_font->setAlpha(m_alpha); + m_font->Print(0.0, top, &theItem->string.c_str()[theItem->begins[at_line]], theItem->breaks[at_line], 0); + } + + top += m_font->getHeight(false); + lines_drawn++; + at_line++; + } + } + + if (pCurrColor != &m_foreground_color) { + m_font->setColor(m_foreground_color); + } + + DrawBottomLine(); } void UIConsole::CharEvent @@ -169,7 +561,36 @@ void UIConsole::CharEvent ) { - // FIXME: stub + if (ch <= 31) { + // Not a valid char for the console + return; + } + + m_refreshcompletionbuffer = true; + + if (m_caret > m_currentline.length()) { + m_caret = m_currentline.length(); + } + + if (m_caret < 0) { + m_caret = 0; + } + + if (m_currentline == m_caret) + { + m_currentline.append(str(char(ch))); + m_caret++; + } + else if (m_caret) + { + m_currentline = str(m_currentline, 0, m_caret) + str(char(ch)) + m_currentline.c_str()[m_caret]; + m_caret++; + } + else + { + m_currentline = str(char(ch)) + m_currentline; + m_caret++; + } } qboolean UIConsole::KeyEvent @@ -179,8 +600,66 @@ qboolean UIConsole::KeyEvent ) { - // FIXME: stub - return qfalse; + if (key != K_TAB && key != K_BACKSPACE) { + m_refreshcompletionbuffer = true; + } + + switch (key) + { + case K_TAB: + break; + + case K_ENTER: + case K_KP_ENTER: + if (m_currentline.length()) { + KeyEnter(); + } + break; + + case K_BACKSPACE: + break; + + case K_UPARROW: + break; + + case K_DOWNARROW: + break; + + case K_LEFTARROW: + if (m_caret > 0) { + m_caret--; + } + break; + + case K_RIGHTARROW: + if (m_caret < m_currentline.length()) { + m_caret++; + } + break; + + case K_DEL: + break; + + case K_PGDN: + break; + + case K_PGUP: + break; + + case K_HOME: + break; + + case K_END: + break; + + case K_MWHEELDOWN: + break; + + case K_MWHEELUP: + break; + } + + return true; } void UIConsole::OnSizeChanged @@ -194,12 +673,17 @@ void UIConsole::OnSizeChanged CLASS_DECLARATION( UIFloatingWindow, UIFloatingConsole, NULL ) { + { &W_Console_ChildSizeChanged, &UIFloatingConsole::OnChildSizeChanged }, + { &UIFloatingConsole::W_ClosePressed, &UIFloatingConsole::OnClosePressed }, { NULL, NULL } }; UIFloatingConsole::UIFloatingConsole() { - // FIXME: stub + m_status = NULL; + m_handler = NULL; + setConsoleColor(UWhite); + setConsoleBackground(UBlack, 1.0); } void UIFloatingConsole::FrameInitialized @@ -208,7 +692,27 @@ void UIFloatingConsole::FrameInitialized ) { - // FIXME: stub + // call the parent initialisation + UIFloatingWindow::FrameInitialized(); + + m_status = new UIStatusBar(alignment_t::WND_ALIGN_BOTTOM, 20.0); + m_status->InitFrame(getChildSpace(), UIRect2D(0, 0, 20.0, 20.0), 0, "verdana-12"); + m_status->EnableSizeBox(this); + m_status->setTitle(str()); + + m_console = new UIConsole(); + m_console->InitFrame(getChildSpace(), UIRect2D(0, 0, 20.0, 20.0), 0, "verdana-12"); + setConsoleColor(m_consoleColor); + setConsoleBackground(m_consoleBackground, m_consoleAlpha); + + Connect(this, W_SizeChanged, W_Console_ChildSizeChanged); + getChildSpace()->AllowActivate(false); + OnChildSizeChanged(NULL); + + m_background_color.a = 1.0; + m_alpha = 1.0; + + getChildSpace()->setBackgroundAlpha(1.0); } void UIFloatingConsole::OnChildSizeChanged @@ -217,7 +721,11 @@ void UIFloatingConsole::OnChildSizeChanged ) { - // FIXME: stub + const UISize2D childSpaceSize = getChildSpace()->getSize(); + const UISize2D statusSize = m_status->getSize(); + const UISize2D newSize(childSpaceSize.width, childSpaceSize.height - statusSize.height); + + m_console->setFrame(UIRect2D(UIPoint2D(0, 0), newSize)); } void UIFloatingConsole::AddText @@ -227,7 +735,9 @@ void UIFloatingConsole::AddText ) { - // FIXME: stub + if (m_console) { + m_console->AddText(text, pColor); + } } void UIFloatingConsole::setConsoleHandler @@ -236,7 +746,11 @@ void UIFloatingConsole::setConsoleHandler ) { - // FIXME: stub + if (m_console) { + m_console->setConsoleHandler(handler); + } else { + m_handler = handler; + } } void UIFloatingConsole::Clear @@ -245,7 +759,9 @@ void UIFloatingConsole::Clear ) { - // FIXME: stub + if (m_console) { + m_console->Clear(); + } } void UIFloatingConsole::OnClosePressed @@ -254,7 +770,7 @@ void UIFloatingConsole::OnClosePressed ) { - // FIXME: stub + SendSignal(UIFloatingWindow::W_ClosePressed); } void UIFloatingConsole::setConsoleBackground @@ -264,7 +780,20 @@ void UIFloatingConsole::setConsoleBackground ) { - // FIXME: stub + m_consoleBackground = color; + m_consoleAlpha = alpha; + + if (m_console) + { + m_console->setBackgroundAlpha(alpha); + m_console->setBackgroundColor(color, true); + } + + if (m_status) + { + m_status->setBackgroundAlpha(alpha); + m_status->setBackgroundColor(color, true); + } } void UIFloatingConsole::setConsoleColor @@ -273,7 +802,15 @@ void UIFloatingConsole::setConsoleColor ) { - // FIXME: stub + m_consoleColor = color; + + if (m_console) { + m_console->setForegroundColor(color); + } + + if (m_status) { + m_status->setForegroundColor(color); + } } CLASS_DECLARATION( UIConsole, UIDMConsole, NULL ) diff --git a/code/uilib/uiconsole.h b/code/uilib/uiconsole.h index 14421b59..976bda1a 100644 --- a/code/uilib/uiconsole.h +++ b/code/uilib/uiconsole.h @@ -50,11 +50,13 @@ item::item() pColor = NULL; } +#define MAX_CONSOLE_ITEMS 300 + class UIConsole : public UIWidget { protected: UList m_history; void *m_historyposition; - item m_items[ 300 ]; + item m_items[MAX_CONSOLE_ITEMS]; str m_currentline; UIVertScroll *m_scroll; int m_firstitem;