--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/guicons/src/guicons.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,1858 @@
+// guicons.cpp
+//
+// Copyright (c) 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+
+#include <fshell/common.mmh>
+#include "guicons.h"
+#include <ImageConversion.h>
+#include <e32Math.h>
+
+#include "defaultfontdata.inl"
+
+const TInt KAttributeMapGranularity = 3;
+
+const ConsoleAttributes::TColor KDefaultForegroundColor = ConsoleAttributes::EBlack;
+const ConsoleAttributes::TColor KDefaultBackgroundColor = ConsoleAttributes::EWhite;
+
+
+ConsoleAttributes::TAttributes DefaultAttributes()
+ {
+ return ConsoleAttributes::TAttributes(ConsoleAttributes::ENone, KDefaultForegroundColor, KDefaultBackgroundColor);
+ }
+
+TRgb MapColor(TUint aAttributes, ConsoleAttributes::TColor aColor)
+ {
+ TRgb rgb;
+
+ switch (aColor)
+ {
+ case ConsoleAttributes::EBlack:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbGray;
+ }
+ else
+ {
+ rgb = KRgbBlack;
+ }
+ break;
+ case ConsoleAttributes::ERed:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbRed;
+ }
+ else
+ {
+ rgb = KRgbDarkRed;
+ }
+ break;
+ case ConsoleAttributes::EGreen:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbGreen;
+ }
+ else
+ {
+ rgb = KRgbDarkGreen;
+ }
+ break;
+ case ConsoleAttributes::EYellow:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbYellow;
+ }
+ else
+ {
+ rgb = KRgbDarkYellow;
+ }
+ break;
+ case ConsoleAttributes::EBlue:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbBlue;
+ }
+ else
+ {
+ rgb = KRgbDarkBlue;
+ }
+ break;
+ case ConsoleAttributes::EMagenta:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbMagenta;
+ }
+ else
+ {
+ rgb = KRgbDarkMagenta;
+ }
+ break;
+ case ConsoleAttributes::ECyan:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbCyan;
+ }
+ else
+ {
+ rgb = KRgbDarkCyan;
+ }
+ break;
+ case ConsoleAttributes::EWhite:
+ if (aAttributes & ConsoleAttributes::EBold)
+ {
+ rgb = KRgbWhite;
+ }
+ else
+ {
+ rgb = KRgbWhite;//KRgbGray;
+ }
+ break;
+ case ConsoleAttributes::EReset:
+ case ConsoleAttributes::EUnchanged:
+ default:
+ ASSERT(EFalse);
+ }
+
+ if (aAttributes & ConsoleAttributes::EInverse)
+ {
+ rgb = ~rgb;
+ }
+
+ return rgb;
+ }
+
+void SignalSemaphore(TAny* aSemaphore)
+ {
+ ((RSemaphore*)aSemaphore)->Signal();
+ }
+
+void CleanupSignalSemaphorePushL(RSemaphore& aSemaphore)
+ {
+ CleanupStack::PushL(TCleanupItem(SignalSemaphore, &aSemaphore));
+ }
+
+void WaitForRequest(TAny* aStatus)
+ {
+ User::WaitForRequest(*(TRequestStatus*)aStatus);
+ }
+
+void CleanupWaitForRequestPushL(TRequestStatus& aStatus)
+ {
+ CleanupStack::PushL(TCleanupItem(WaitForRequest, &aStatus));
+ }
+
+//______________________________________________________________________________
+// CConsoleControl
+EXPORT_C CConsoleControl* CConsoleControl::NewL(TInt aBufferSize, MConsoleUi* aUi)
+ {
+ CConsoleControl* self = new(ELeave)CConsoleControl(aUi, aBufferSize);
+ CleanupStack::PushL(self);
+ self->ConstructL(CConsoleFont::NewL(KDefaultFontImageData));
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CConsoleControl* CConsoleControl::NewL(TInt aBufferSize, const TDesC& aFontFile, MConsoleUi* aUi)
+ {
+ CConsoleControl* self = new(ELeave)CConsoleControl(aUi, aBufferSize);
+ CleanupStack::PushL(self);
+ self->ConstructL(CConsoleFont::NewL(aFontFile));
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CConsoleControl::~CConsoleControl()
+ {
+ delete iBlinkTimer;
+ delete iFont;
+ iCursor.Hide();
+ iBuffer.ResetAndDestroy();
+ iKeyQueue.Close();
+ }
+
+EXPORT_C void CConsoleControl::Closed()
+ {
+ if (iUi)
+ {
+ iUi->HandleConsoleClosed(this);
+ }
+ }
+
+EXPORT_C void CConsoleControl::Draw(const TRect& aRect) const
+ {
+ CWindowGc& gc = SystemGc();
+ gc.SetBrushStyle(CGraphicsContext::ENullBrush);
+ gc.SetPenStyle(CGraphicsContext::ENullPen);
+ // Need to do a clear here, to ensure we actually draw to all the pixels in aRect that we've been asked to draw. If we don't do that, wserv generally gets upset.
+// gc.SetBrushColor(KDefaultBackgroundColor);
+// gc.Clear(aRect);
+
+ for (TInt y=0; y<iSizeChars.iHeight; ++y)
+ {
+ TViewPosition line(*this, 0, y);
+ if (aRect.Intersects(LineRect(line)))
+ {
+ DrawLine(line, gc);
+ }
+ }
+
+ if (iDrawNavigator)
+ {
+ // And draw the 5-way UI
+#ifdef FSHELL_WSERV2_SUPPORT
+ // XOR draw mode doesn't seem to be supported in recent wserv, so use a colour with alpha channel instead
+ const TRgb col(15, 15, 15, 128);
+ gc.SetDrawMode(CGraphicsContext::EDrawModePEN);
+#else
+ const TRgb col(15,15,15);
+ gc.SetDrawMode(CGraphicsContext::EDrawModeXOR);
+#endif
+ gc.SetBrushColor(col);
+ gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+ gc.SetPenColor(col);
+ for (TInt i = 0; i < ENumButtons; i++)
+ {
+ if (aRect.Intersects(iButtonRects[i]))
+ {
+ if (i == ECenter)
+ {
+ gc.DrawEllipse(iButtonRects[i]);
+ }
+ else
+ {
+ gc.DrawRect(iButtonRects[i]);
+ }
+ }
+ }
+ }
+ }
+
+EXPORT_C TCoeInputCapabilities CConsoleControl::InputCapabilities() const
+ {
+ return TCoeInputCapabilities(
+ TCoeInputCapabilities::ENonPredictive
+ | TCoeInputCapabilities::EAllText
+ | TCoeInputCapabilities::ENavigation
+ );
+ }
+
+EXPORT_C void CConsoleControl::FocusChanged(TDrawNow)
+ {
+ iCursor.Update();
+ if (IsFocused())
+ {
+ StartBlinking();
+ }
+ else
+ {
+ iBlinkTimer->Cancel();
+ }
+ }
+
+EXPORT_C void CConsoleControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
+ {
+ if (aPointerEvent.iType == TPointerEvent::EButton1Down)
+ {
+ for (TInt i = 0; i < ENumButtons; i++)
+ {
+ if (iButtonRects[i].Contains(aPointerEvent.iPosition))
+ {
+ SimulateKeyL((TButton)i);
+ iIgnoringDrags = ETrue;
+ return;
+ }
+ }
+ iIgnoringDrags = EFalse;
+ }
+
+ if (iIgnoringDrags) return;
+ if (aPointerEvent.iType == TPointerEvent::EButton1Down)
+ {
+ iDragStart = aPointerEvent.iPosition;
+ }
+ if (aPointerEvent.iType == TPointerEvent::EDrag)
+ {
+ TPoint delta = iDragStart - aPointerEvent.iPosition;
+ TInt lines = delta.iY / iFont->GlyphSize().iHeight;
+ if (lines)
+ {
+ iViewWindow.iY += lines;
+ ViewMoved();
+
+ iDragStart.iY -= (lines * iFont->GlyphSize().iHeight);
+ }
+ }
+ }
+
+EXPORT_C TKeyResponse CConsoleControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
+ {
+ if ((!IsFocused()) || IsNonFocusing()) return EKeyWasNotConsumed;
+
+ if (aType == EEventKey)
+ {
+ iKeyQueue.AppendL(aKeyEvent);
+ SendKey();
+
+#ifdef LOCAL_ECHO
+ TUint code = aKeyEvent.iCode;
+ if (code == '\r') code = '\n';
+
+ TBuf<0x20> ip;
+ ip.AppendFormat(_L("key %d"), code);
+ User::InfoPrint(ip);
+
+ TBuf<1> buf;
+ buf.Append(TChar(code));
+ Write(buf);
+#endif
+ return EKeyWasConsumed;
+ }
+ return EKeyWasNotConsumed;
+ }
+
+EXPORT_C void CConsoleControl::InjectKeysL(const TDesC& aKeys)
+ {
+ for (TInt i=0; i<aKeys.Length(); ++i)
+ {
+ TKeyEvent key;
+ key.iCode = aKeys[i];
+ key.iModifiers = 0;
+ iKeyQueue.AppendL(key);
+ }
+ SendKey();
+ }
+
+void CConsoleControl::DrawLine(TViewPosition aLine, CBitmapContext& aDrawTo) const
+ {
+ CConsoleLine* line = GetLine(aLine);
+ if (line)
+ {
+ line->Draw(aDrawTo, aLine);
+ }
+ }
+
+TRect CConsoleControl::LineRect(TViewPosition aLine) const
+ {
+ return TRect(TScreenPosition(aLine).iPoint, TSize(iFont->GlyphSize().iWidth * iSizeChars.iWidth, iFont->GlyphSize().iHeight));
+ }
+
+
+EXPORT_C void CConsoleControl::SizeChanged()
+ {
+ TSize sizePixels = Size();
+ TSize newSizeChars(sizePixels.iWidth / iFont->GlyphSize().iWidth, sizePixels.iHeight / iFont->GlyphSize().iHeight);
+ if (newSizeChars != iSizeChars)
+ {
+ iSizeChars = newSizeChars;
+ TRAP_IGNORE(SizeChangedL());
+ }
+ }
+
+CConsoleControl::CConsoleControl(MConsoleUi* aUi, TInt aBufferSize)
+ : iUi(aUi), iCursor(*this), iCurrentAttributes(ConsoleAttributes::ENone, KDefaultForegroundColor, KDefaultBackgroundColor), iBufferSize(aBufferSize)
+ {
+ }
+
+void CConsoleControl::ConstructL(CConsoleFont* aFont)
+ {
+ iBlinkTimer = CPeriodic::NewL(CActive::EPriorityStandard);
+ iFont = aFont;
+ iCursor.SetFont(*iFont);
+ SetCursorHeight(KDefaultCursorHeightPercentage);
+ }
+
+void CConsoleControl::SizeChangedL()
+ {
+ TInt bufferSize = Max(iBufferSize, iSizeChars.iHeight);
+ for (TInt i=0; i<Min(iBuffer.Count(), bufferSize); ++i)
+ {
+ iBuffer[i]->SetWidthL(iSizeChars.iWidth);
+ }
+ while (iBuffer.Count() < bufferSize)
+ {
+ CConsoleLine* line = CConsoleLine::NewL(*this, *iFont, iSizeChars.iWidth);
+ CleanupStack::PushL(line);
+ iBuffer.AppendL(line);
+ CleanupStack::Pop();
+ }
+ while (iBuffer.Count() > bufferSize)
+ {
+ delete iBuffer[iBuffer.Count()-1];
+ iBuffer.Remove(iBuffer.Count()-1);
+ }
+ iCursor.Update();
+
+ if (FivewayNavIsDisplaying()) SetDisplayFivewayNav(ETrue); // re-layout the onscreen nav if applicable
+ }
+
+CConsoleLine* CConsoleControl::GetLine(TBufferPosition aLine) const
+ {
+ return iBuffer[aLine.iPoint.iY];
+ }
+
+TPoint CConsoleControl::ViewPosition() const
+ {
+ return iViewWindow;
+ }
+
+TPoint CConsoleControl::CursorWindowPosition() const
+ {
+ return iCursorWindow;
+ }
+
+TSize CConsoleControl::GlyphSize() const
+ {
+ return iFont->GlyphSize();
+ }
+
+TBool CConsoleControl::IsSpecialChar(TChar aChar) const
+ {
+ switch(aChar)
+ {
+ case 0x00: // Null.
+ case 0x07: // Bell.
+ case 0x08: // Backspace.
+ case 0x7f: // Delete.
+ case 0x09: // Tab.
+ case 0x0a: // Line feed.
+ case 0x0b: // Vertical tab.
+ case 0x0c: // Form feed.
+ case 0x0d: // Carriage return.
+ return ETrue;
+ default:
+ return EFalse;
+ }
+ }
+
+void CConsoleControl::HandleSpecialChar(TChar aChar)
+ {
+ switch(aChar)
+ {
+ case 0x00: // Null.
+ break;
+ case 0x07: // Bell.
+ break;
+ case 0x08: // Backspace.
+ case 0x7f: // Delete.
+ iCursor--;
+ break;
+ case 0x09: // horizontal tab
+ iCursor += KTabSize - (iCursor.Position().iPoint.iX % KTabSize);
+ break;
+ case 0x0a: // line feed
+ iCursor -= iCursor.Position().iPoint.iX;
+ iCursor.Down();
+ break;
+ case 0x0b: // Vertical tab.
+ break;
+ case 0x0c: // Form feed
+ ClearScreen();
+ break;
+ case 0x0d: // carriage return
+ iCursor -= iCursor.Position().iPoint.iX;
+ break;
+ default:
+ User::Invariant();
+ }
+ }
+
+void CConsoleControl::SendKey()
+ {
+ if (iReader && iKeyQueue.Count())
+ {
+ iCurrentKey = iKeyQueue[0];
+ iKeyQueue.Remove(0);
+ iReader->ReadComplete(KErrNone);
+ iReader = NULL;
+ }
+ }
+
+EXPORT_C void CConsoleControl::Read(MGuiConsoleReader& aReader)
+ {
+ if (iReader)
+ {
+ aReader.ReadComplete(KErrInUse);
+ }
+ else
+ {
+ iReader = &aReader;
+ SendKey();
+ }
+ }
+
+EXPORT_C void CConsoleControl::ReadCancel()
+ {
+ iReader = NULL;
+ }
+
+EXPORT_C void CConsoleControl::Write(const TDesC &aDes)
+ {
+ TRAP_IGNORE(WriteL(aDes));
+ }
+
+void CConsoleControl::WriteL(const TDesC &aDes)
+ {
+ TRect invalidRect;
+ for (TInt i=0; i<aDes.Length(); ++i)
+ {
+ if (IsSpecialChar(aDes[i]))
+ {
+ if (!invalidRect.IsEmpty())
+ {
+ // Draw to the invalid rectangle before handling this special character because it may cause the
+ // window to scroll, thereby invalidating the coordinates of invalidRect.
+ DrawNow(invalidRect);
+ invalidRect = TRect();
+ }
+ HandleSpecialChar(aDes[i]);
+ }
+ else
+ {
+ CConsoleLine* line = GetLine(iCursor.Position());
+ line->SetL(iCursor.Position().iPoint.iX, aDes[i], iCurrentAttributes);
+ TRect lineRect(LineRect(iCursor.Position()));
+ Window().Invalidate(lineRect);
+ if (invalidRect.IsEmpty())
+ {
+ invalidRect = lineRect;
+ }
+ else
+ {
+ invalidRect.BoundingRect(lineRect);
+ }
+ iCursor++;
+ }
+ }
+
+ if (!invalidRect.IsEmpty())
+ {
+ DrawNow(invalidRect);
+ }
+
+ iCursor.Update();
+ }
+
+void CConsoleControl::StartBlinking()
+ {
+ if (!iBlinkTimer->IsActive())
+ {
+ iBlinkTimer->Start(500000, 500000, TCallBack(BlinkCallback, this));
+ }
+ }
+
+TInt CConsoleControl::BlinkCallback(TAny* aPtr)
+ {
+ CConsoleControl* self = static_cast<CConsoleControl*>(aPtr);
+
+ TBool neededToBlink(EFalse);
+ for (TInt y = 0; y < self->iSizeChars.iHeight; ++y)
+ {
+ TViewPosition line(*self, 0, y);
+ if (self->GetLine(line)->NeedToBlink(self->iBlinkOn))
+ {
+ neededToBlink = ETrue;
+ self->Window().Invalidate(self->LineRect(line));
+ }
+ }
+ if (neededToBlink)
+ {
+ self->iBlinkOn = !self->iBlinkOn;
+ }
+ else
+ {
+ self->iBlinkTimer->Cancel();
+ }
+
+ return KErrNone;
+ }
+
+EXPORT_C void CConsoleControl::ViewScrollUp()
+ {
+ iViewWindow.iY--;
+ ViewMoved();
+ }
+
+EXPORT_C void CConsoleControl::ViewScrollDown()
+ {
+ iViewWindow.iY++;
+ ViewMoved();
+ }
+
+EXPORT_C void CConsoleControl::ViewPageUp()
+ {
+ iViewWindow.iY -= iSizeChars.iHeight-1;
+ ViewMoved();
+ }
+
+EXPORT_C void CConsoleControl::ViewPageDown()
+ {
+ iViewWindow.iY += iSizeChars.iHeight-1;
+ ViewMoved();
+ }
+
+EXPORT_C void CConsoleControl::ViewHome()
+ {
+ iViewWindow.iY = 0;
+ ViewMoved();
+ }
+
+EXPORT_C void CConsoleControl::ViewEnd()
+ {
+ iViewWindow = iCursorWindow;
+ ViewMoved();
+ }
+
+void CConsoleControl::Invalidate5Way()
+ {
+ if (iDrawNavigator)
+ {
+ for (TInt i = 0; i < ENumButtons; i++)
+ {
+ Window().Invalidate(iButtonRects[i]);
+ }
+ }
+ }
+
+EXPORT_C TInt CConsoleControl::SetAttributes(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor)
+ {
+ ConsoleAttributes::TAttributes currentAttributes = iCurrentAttributes;
+
+ if (aAttributes == ConsoleAttributes::ENone)
+ {
+ currentAttributes = DefaultAttributes();
+ }
+ else
+ {
+ currentAttributes.iAttributes = aAttributes;
+ }
+
+ switch (aForegroundColor)
+ {
+ case ConsoleAttributes::EReset:
+ currentAttributes.iForegroundColor = KDefaultForegroundColor;
+ break;
+ case ConsoleAttributes::EUnchanged:
+ // Do nothing.
+ break;
+ default:
+ currentAttributes.iForegroundColor = aForegroundColor;
+ break;
+ }
+
+ switch (aBackgroundColor)
+ {
+ case ConsoleAttributes::EReset:
+ currentAttributes.iBackgroundColor = KDefaultBackgroundColor;
+ break;
+ case ConsoleAttributes::EUnchanged:
+ // Do nothing.
+ break;
+ default:
+ currentAttributes.iBackgroundColor = aBackgroundColor;
+ break;
+ }
+
+ TRAPD(err, iFont->PrepareForegroundColorL(MapColor(currentAttributes.iAttributes, currentAttributes.iForegroundColor)));
+ if (err == KErrNone)
+ {
+ iCurrentAttributes = currentAttributes;
+ }
+
+ return err;
+ }
+
+void CConsoleControl::ViewMoved()
+ {
+ if (iViewWindow.iY < 0) iViewWindow.iY = 0;
+ if (iViewWindow.iY + iSizeChars.iHeight > iBuffer.Count()) iViewWindow.iY = iBuffer.Count() - iSizeChars.iHeight;
+ Window().Invalidate();
+ }
+
+void CConsoleControl::CursorWindowScrollDown()
+ {
+ TBool viewWindowMatchesCursorWindow = (iViewWindow.iY == iCursorWindow.iY);
+ iCursorWindow.iY++;
+ if (iCursorWindow.iY + iSizeChars.iHeight > iBuffer.Count())
+ {
+ iCursorWindow.iY--;
+ CConsoleLine* topLine = iBuffer[0];
+ iBuffer.Remove(0);
+ topLine->Clear();
+ iBuffer.Append(topLine);
+
+ // JB - Disabled the code below because it forces a full redraw of the window which seems
+ // unnecessary, particularly now that this function trys to efficiently scroll using
+ // RDrawableWindow::Scroll. Note though that I can't claim to fully understand this code,
+ // so this may be a dumb thing to do. Original comment follows...
+ // move this up so that the text in the view window moves up with the scrolling text.
+ // ViewScrollUp();
+ }
+
+ if (viewWindowMatchesCursorWindow) // keep them in sync if they were when we started
+ {
+ iViewWindow.iY = iCursorWindow.iY;
+ }
+
+#ifndef FSHELL_WSERV2_SUPPORT
+ // On wserv1 we can't use Scroll if we're showing the 5-way nav - it looks bad
+ if (iDrawNavigator)
+ {
+ DrawDeferred();
+ }
+ else
+#endif
+ {
+ // on wserv2, or wserv1 when the 5-way nav isn't displayed, we can use RWindow::Scroll for better performance (although, performance only seems to be a problem on wserv1 with a wide screen. On wserv2 probably just a DrawDeferred() would be sufficient)
+ Invalidate5Way();
+ Window().Scroll(Rect(), TPoint(0, -(iFont->GlyphSize().iHeight)));
+ Invalidate5Way();
+ TRect invalidRect(LineRect(TViewPosition(*this, 0, iSizeChars.iHeight - 1)));
+ Window().Invalidate(invalidRect);
+ }
+ }
+
+EXPORT_C TPoint CConsoleControl::CursorPos() const
+ {
+ return iCursor.Position().iPoint;
+ }
+
+EXPORT_C void CConsoleControl::SetCursorPosAbs(const TPoint &aPoint)
+ {
+ iCursor.SetPosAbs(TConsCursorPosition(*this, aPoint));
+ iCursor.Update();
+ }
+
+EXPORT_C void CConsoleControl::SetCursorPosRel(const TPoint &aPoint)
+ {
+ iCursor.SetPosRel(TConsCursorPosition(*this, aPoint));
+ iCursor.Update();
+ }
+
+EXPORT_C void CConsoleControl::SetCursorHeight(TInt aPercentage)
+ {
+ iCursor.SetHeight(aPercentage);
+ iCursor.Update();
+ }
+
+EXPORT_C void CConsoleControl::SetTitle(const TDesC &aTitle)
+ {
+ if (iUi)
+ {
+ TRAP_IGNORE(iUi->ConsoleTitleChangedL(this, aTitle));
+ }
+ }
+
+EXPORT_C void CConsoleControl::ClearScreen()
+ {
+ Window().Invalidate();
+ for (TInt y=0; y<iBuffer.Count(); ++y)
+ {
+ iBuffer[y]->Clear();
+ }
+ iCursorWindow.iY = 0;
+ iViewWindow.iY = 0;
+ iCursor.SetPosAbs(TConsCursorPosition(*this, 0,0));
+ iCurrentAttributes = DefaultAttributes();
+ }
+
+EXPORT_C void CConsoleControl::ClearToEndOfLine()
+ {
+ GetLine(iCursor.Position())->ClearFrom(iCursor.Position());
+ Window().Invalidate(LineRect(iCursor.Position()));
+ }
+
+EXPORT_C TSize CConsoleControl::ScreenSize() const
+ {
+ return iSizeChars;
+ }
+
+EXPORT_C TKeyCode CConsoleControl::KeyCode() const
+ {
+ return (TKeyCode)iCurrentKey.iCode;
+ }
+
+EXPORT_C TUint CConsoleControl::KeyModifiers() const
+ {
+ return iCurrentKey.iModifiers;
+ }
+
+void CConsoleControl::SimulateKeyL(TButton aButton)
+ {
+ TKeyEvent key;
+ key.iRepeats = 0;
+ key.iModifiers = 0;
+ switch (aButton)
+ {
+ case EUp:
+ key.iCode = EKeyUpArrow;
+ key.iScanCode = EStdKeyUpArrow;
+ break;
+ case EDown:
+ key.iCode = EKeyDownArrow;
+ key.iScanCode = EStdKeyDownArrow;
+ break;
+ case ELeft:
+ key.iCode = EKeyLeftArrow;
+ key.iScanCode = EStdKeyLeftArrow;
+ break;
+ case ERight:
+ key.iCode = EKeyRightArrow;
+ key.iScanCode = EStdKeyRightArrow;
+ break;
+ case ECenter:
+ key.iCode = EKeyEnter;
+ key.iScanCode = EStdKeyEnter;
+ break;
+ default:
+ return;
+ }
+ iCoeEnv->SimulateKeyEventL(key, EEventKey);
+ }
+
+EXPORT_C TBool CConsoleControl::FivewayNavIsDisplaying() const
+ {
+ return iButtonRects[ECenter].Width();
+ }
+
+EXPORT_C void CConsoleControl::SetDisplayFivewayNav(TBool aShow)
+ {
+ if (aShow)
+ {
+ TRect rect(Rect());
+ TInt shortLen = Min(rect.Width(), rect.Height()); // Look nicer in landscape
+ TSize buttonSize(shortLen / 4, shortLen / 4);
+ TRect center(TPoint(rect.Width()/2 - buttonSize.iWidth/2, rect.Height() - 2*buttonSize.iHeight), buttonSize);
+ iButtonRects[ECenter] = center;
+ iButtonRects[ECenter].Shrink(5, 5);
+ iButtonRects[ELeft] = center; iButtonRects[ELeft].Move(-buttonSize.iWidth, 0);
+ iButtonRects[ERight] = center; iButtonRects[ERight].Move(buttonSize.iWidth, 0);
+ iButtonRects[EUp] = center; iButtonRects[EUp].Move(0, -buttonSize.iHeight);
+ iButtonRects[EDown] = center; iButtonRects[EDown].Move(0, buttonSize.iHeight);
+ iDrawNavigator = ETrue;
+ }
+ else
+ {
+ Mem::FillZ(iButtonRects, sizeof(iButtonRects));
+ }
+ DrawDeferred();
+ }
+
+void CConsoleControl::ActivateL()
+ {
+ Window().SetBackgroundColor(KRgbWhite);
+ CCoeControl::ActivateL();
+ }
+
+//______________________________________________________________________________
+// Image loader thread
+// We use ICl to decode the font image. Despite ICL having the ability to create
+// a thread of it own to do the decoding, when we decode from a descriptor
+// (instead of a file), it still requires a AO RunL's in out thread to operate.
+// So, we have to create a new thread manually so that we can always load images
+// synchronously.
+
+class RImageDecodeThreadParams
+ {
+public:
+ RImageDecodeThreadParams(const TDesC& aFileName)
+ : iMode(EDecodeFile), iFileName(aFileName), iData(KNullDesC8), iBitmapHandle(KNullHandle) {}
+ RImageDecodeThreadParams(const TDesC8& aImageData)
+ : iMode(EDecodeData), iFileName(KNullDesC), iData(aImageData), iBitmapHandle(KNullHandle) {}
+ TInt Open()
+ {
+ TInt err = iBitmapReadySemaphore.CreateLocal(0);
+ if (err==KErrNone) err = iThreadExitSemaphore.CreateLocal(0);
+ if (err!=KErrNone) Close();
+ return err;
+ }
+ void Close()
+ {
+ iBitmapReadySemaphore.Close();
+ iThreadExitSemaphore.Close();
+ }
+public:
+ enum
+ {
+ EDecodeFile,
+ EDecodeData,
+ } iMode;
+ const TPtrC iFileName;
+ const TPtrC8 iData;
+ TFrameInfo iFrameInfo;
+ TInt iBitmapHandle;
+ RSemaphore iBitmapReadySemaphore;
+ RSemaphore iThreadExitSemaphore;
+ TInt iThreadError;
+ };
+
+class CImageDecodeWaiter : public CActive
+ {
+public:
+ CImageDecodeWaiter(TInt aPriority)
+ : CActive(aPriority)
+ {
+ CActiveScheduler::Add(this);
+ }
+ void Start(CImageDecoder* aDecoder, CFbsBitmap* aBitmap)
+ {
+ TRequestStatus* stat = &iStatus;
+ aDecoder->Convert(stat, *aBitmap);
+ SetActive();
+ CActiveScheduler::Start();
+ }
+ virtual void RunL()
+ {
+ iCompletionErr = iStatus.Int();
+ CActiveScheduler::Stop();
+ }
+ virtual void DoCancel() {}
+public:
+ TInt iCompletionErr;
+ };
+
+void ImageDecodeThreadL(RImageDecodeThreadParams& aParams)
+ {
+ User::LeaveIfError(RFbsSession::Connect());
+
+ CActiveScheduler* as = new(ELeave)CActiveScheduler;
+ CActiveScheduler::Install(as);
+ CleanupStack::PushL(as);
+
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+ User::LeaveIfError(fs.ShareAuto());
+
+ CImageDecoder* dec = NULL;
+ switch (aParams.iMode)
+ {
+ case RImageDecodeThreadParams::EDecodeFile:
+ dec = CImageDecoder::FileNewL(fs, aParams.iFileName);
+ break;
+ case RImageDecodeThreadParams::EDecodeData:
+ dec = CImageDecoder::DataNewL(fs, aParams.iData);
+ break;
+ }
+ CleanupStack::PushL(dec);
+
+ aParams.iFrameInfo = dec->FrameInfo();
+ CFbsBitmap* bmp = new(ELeave)CFbsBitmap;
+ CleanupStack::PushL(bmp);
+ User::LeaveIfError(bmp->Create(aParams.iFrameInfo.iOverallSizeInPixels, aParams.iFrameInfo.iFrameDisplayMode));
+
+
+ CImageDecodeWaiter* waiter = new(ELeave)CImageDecodeWaiter(CActive::EPriorityStandard);
+ CleanupStack::PushL(waiter);
+
+ waiter->Start(dec, bmp);
+ User::LeaveIfError(waiter->iCompletionErr);
+
+ aParams.iBitmapHandle = bmp->Handle();
+ aParams.iThreadError = KErrNone;
+ aParams.iBitmapReadySemaphore.Signal();
+ aParams.iThreadExitSemaphore.Wait();
+
+ CleanupStack::PopAndDestroy(5, as); // as, fs, dec, bmp, waiter
+ }
+
+TInt ImageDecodeThead(TAny* aParams)
+ {
+ User::SetCritical(User::EProcessCritical);
+ __UHEAP_MARK;
+ RImageDecodeThreadParams* params = (RImageDecodeThreadParams*)aParams;
+
+ CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack
+ if (!cleanup) return KErrNoMemory;
+ TRAPD(err, ImageDecodeThreadL(*params));
+ params->iThreadError = err;
+ if (err!=KErrNone)
+ {
+ params->iBitmapReadySemaphore.Signal();
+ }
+
+ delete cleanup;
+ REComSession::FinalClose();
+ RFbsSession::Disconnect();
+ __UHEAP_MARKEND;
+ User::SetCritical(User::ENotCritical);
+ return err;
+ }
+
+//______________________________________________________________________________
+// CConsoleFont
+EXPORT_C CConsoleFont* CConsoleFont::NewL(const TDesC& aFontFile)
+ {
+ CConsoleFont* self = new(ELeave)CConsoleFont;
+ CleanupStack::PushL(self);
+ self->ConstructL(aFontFile);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CConsoleFont* CConsoleFont::NewL(const TDesC8& aEncodedFontImage)
+ {
+ CConsoleFont* self = new(ELeave)CConsoleFont;
+ CleanupStack::PushL(self);
+ self->ConstructL(aEncodedFontImage);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CConsoleFont::~CConsoleFont()
+ {
+ for (TInt i = 0; i < KNumGlyphs; ++i)
+ {
+ delete iChars[i];
+ }
+ for (TInt i = 0; i < KNumColors; ++i)
+ {
+ delete iColors[i];
+ }
+ }
+
+EXPORT_C TSize CConsoleFont::GlyphSize() const
+ {
+ return iGlyphRect.Size();
+ }
+
+
+EXPORT_C void CConsoleFont::DrawChar(TChar aChar, CBitmapContext& aDrawTo, TPoint aPosPixels, TRgb aColor)
+ {
+ // Note, this method assumes that the glyph's background has already been set to the appropriate color.
+
+ if ((aChar < KFontBitmapFirstCharCode) || (aChar > KFontBitmapLastCharCode))
+ {
+ aChar = KFontBitmapLastCharCode;
+ }
+
+ aDrawTo.BitBltMasked(aPosPixels, ForegroundBitmap(aColor), iGlyphRect, iChars[(TInt)aChar - KFontBitmapFirstCharCode], ETrue);
+ }
+
+CConsoleFont::CConsoleFont()
+ {
+ }
+
+void CConsoleFont::ConstructL(const TDesC& aFontFile)
+ {
+ RImageDecodeThreadParams decodeParams(aFontFile);
+ ConstructL(decodeParams);
+ }
+
+void CConsoleFont::ConstructL(const TDesC8& aEncodedFontImage)
+ {
+ RImageDecodeThreadParams decodeParams(aEncodedFontImage);
+ ConstructL(decodeParams);
+ }
+
+_LIT(KImageDecodeThreadNameFmt, "ImageDecodeThread%08x");
+
+void CConsoleFont::ConstructL(RImageDecodeThreadParams& aDecodeParams)
+ {
+ User::LeaveIfError(aDecodeParams.Open());
+ CleanupClosePushL(aDecodeParams);
+ RThread decodeThread;
+ CleanupClosePushL(decodeThread);
+ // kick off the sub thread doing the decoding
+ TInt err;
+ TInt seq = 0;
+ do
+ {
+ TBuf<0x20> threadName;
+ threadName.AppendFormat(KImageDecodeThreadNameFmt, seq);
+ err = decodeThread.Create(threadName, ImageDecodeThead, KDefaultStackSize, 0x1000, 0x200000, &aDecodeParams);
+ seq++;
+ } while (err==KErrAlreadyExists);
+ User::LeaveIfError(err);
+ decodeThread.Resume();
+
+ TRequestStatus threadExit;
+ decodeThread.Logon(threadExit);
+
+ CleanupWaitForRequestPushL(threadExit); // things will probably go wrong if we leave on this line
+ CleanupSignalSemaphorePushL(aDecodeParams.iThreadExitSemaphore);
+
+ /*
+ Now, on the cleanup stack we have:
+ 1. iThreadExitSemaphore.Signal()
+ 2. WaitForRequest(threadExit)
+ 3. decodeThread
+ 4. aDecodeParams
+
+ So, if we leave now:
+ 1. We will signal the sub thread to exit
+ 2. We will then wait for the sub thread to exit
+ 3. close the sub thread handle
+ 4. close aDecodeParams, which will destroy the semaphores
+
+ Note, it's important that we wait for the thread to exit before the cleanup stack
+ if fully unwound, as if we destroy the semaphores before the sub thread has exitted,
+ then it will panic with KERN-EXEC 0.
+ */
+
+ // wait for it to decode the bitmap (or die)
+ aDecodeParams.iBitmapReadySemaphore.Wait();
+ User::LeaveIfError(aDecodeParams.iThreadError); // we will leave here if there was an error in the subthread
+
+ // process decoded image
+ TSize bmpSize = aDecodeParams.iFrameInfo.iOverallSizeInPixels;
+ if (bmpSize.iWidth % KFontBitmapWidthChars) User::Leave(KErrCorrupt);// better error code / panic?
+ if (bmpSize.iHeight % KFontBitmapHeightChars) User::Leave(KErrCorrupt);// better error code / panic?
+ iGlyphRect = TRect(TPoint(0, 0), TSize(bmpSize.iWidth / KFontBitmapWidthChars, bmpSize.iHeight / KFontBitmapHeightChars));
+
+ CFbsBitmap* allChars = new(ELeave)CFbsBitmap();
+ CleanupStack::PushL(allChars);
+ User::LeaveIfError(allChars->Duplicate(aDecodeParams.iBitmapHandle));
+
+ for (TInt i = 0; i < KNumGlyphs; ++i)
+ {
+ iChars[i] = new(ELeave)CFbsBitmap;
+ User::LeaveIfError(iChars[i]->Create(iGlyphRect.Size(), EGray2));
+
+ CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(iChars[i]);
+ CleanupStack::PushL(bitmapDevice);
+
+ CBitmapContext* bitmapContext;
+ User::LeaveIfError(bitmapDevice->CreateBitmapContext(bitmapContext));
+ CleanupStack::PushL(bitmapContext);
+
+ TPoint charPos(i % KFontBitmapWidthChars, i / KFontBitmapWidthChars);
+ TPoint pixelPos(charPos.iX * iGlyphRect.Size().iWidth, charPos.iY * iGlyphRect.Size().iHeight);
+ TRect charRect(pixelPos, iGlyphRect.Size());
+ bitmapContext->BitBlt(TPoint(0, 0), allChars, charRect);
+
+ CleanupStack::PopAndDestroy(2, bitmapDevice);
+ }
+
+ // this will clean everything up - see above comment.
+ CleanupStack::PopAndDestroy(5, &aDecodeParams); // decodeThread, aDecodeParams
+
+ PrepareForegroundColorL(KDefaultForegroundColor);
+ }
+
+void CConsoleFont::PrepareForegroundColorL(TRgb aColor)
+ {
+ CFbsBitmap* bitmap = ForegroundBitmap(aColor);
+ if (bitmap == NULL)
+ {
+ bitmap = new(ELeave)CFbsBitmap;
+ CleanupStack::PushL(bitmap);
+ User::LeaveIfError(bitmap->Create(iGlyphRect.Size(), EColor16));
+ CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(bitmap);
+ CleanupStack::PushL(bitmapDevice);
+ CBitmapContext* bitmapContext;
+ User::LeaveIfError(bitmapDevice->CreateBitmapContext(bitmapContext));
+ CleanupStack::PushL(bitmapContext);
+ bitmapContext->SetBrushColor(aColor);
+ bitmapContext->SetPenStyle(CGraphicsContext::ENullPen);
+ bitmapContext->SetBrushStyle(CGraphicsContext::ESolidBrush);
+ bitmapContext->DrawRect(iGlyphRect);
+ CleanupStack::PopAndDestroy(2, bitmapDevice);
+ CleanupStack::Pop(bitmap);
+ iColors[aColor.Color16()] = bitmap;
+ }
+ }
+
+CFbsBitmap* CConsoleFont::ForegroundBitmap(TRgb aColor)
+ {
+ return iColors[aColor.Color16()];
+ }
+
+//______________________________________________________________________________
+// CConsoleLine
+CConsoleLine* CConsoleLine::NewL(CConsoleControl& aControl, const CConsoleFont& aFont, TInt aWidth)
+ {
+ CConsoleLine* self = new(ELeave)CConsoleLine(aControl, aFont);
+ CleanupStack::PushL(self);
+ self->ConstructL(aWidth);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CConsoleLine::~CConsoleLine()
+ {
+ iText.Close();
+ iAttributeMap.Close();
+ }
+
+void CConsoleLine::SetWidthL(TInt aNewWidth)
+ {
+ if (aNewWidth != iWidth)
+ {
+ RBuf8 newText;
+ newText.CreateL(aNewWidth);
+ newText.Copy(iText.Left(aNewWidth));
+ newText.Swap(iText);
+ newText.Close();
+ iWidth = aNewWidth;
+ iAttributeMap.RemoveFrom(aNewWidth);
+ }
+ }
+
+void CConsoleLine::SetL(TInt aIndex, TUint8 aChar, const ConsoleAttributes::TAttributes& aAttributes)
+ {
+ __ASSERT_ALWAYS((aIndex < iWidth)&&(aIndex>=0), User::Invariant());
+ iAttributeMap.AddL(aIndex, iWidth, aAttributes);
+ if (aIndex > iText.Length())
+ {
+ TInt oldLen = iText.Length();
+ iText.SetLength(aIndex);
+ iText.MidTPtr(oldLen).Fill(' ');
+ iText.Append(aChar);
+ }
+ else if (aIndex == iText.Length())
+ {
+ iText.Append(aChar);
+ }
+ else
+ {
+ iText[aIndex] = aChar;
+ }
+ }
+
+void CConsoleLine::Clear()
+ {
+ iAttributeMap.Reset();
+ iText.Zero();
+ }
+
+void CConsoleLine::ClearFrom(TBufferPosition aPos)
+ {
+ TInt pos = Min(aPos.iPoint.iX, iText.Length());
+ iText.SetLength(pos);
+ iAttributeMap.RemoveFrom(pos);
+ }
+
+void CConsoleLine::Draw(CBitmapContext& aDrawTo, TViewPosition aViewPosition) const
+ {
+ const TSize glyphSize(iFont.GlyphSize());
+
+ TScreenPosition screenPos(aViewPosition);
+ TRect rectToClear(screenPos.iPoint, TScreenPosition(aViewPosition.iConsole, 0, (aViewPosition.iPoint.iY + 1) * glyphSize.iHeight).iPoint);
+
+ const TInt numAttributeBlocks = iAttributeMap.NumberOfBlocks();
+ for (TInt i = 0; i < numAttributeBlocks; ++i)
+ {
+ TInt startXPos = 0;
+ TInt endXPos = 0;
+ ConsoleAttributes::TAttributes attributes(ConsoleAttributes::ENone);
+ iAttributeMap.GetBlock(i, iWidth, startXPos, endXPos, attributes);
+
+ // Draw the background in the appropriate color in one hit.
+ rectToClear.iTl.iX = screenPos.iPoint.iX + (startXPos * glyphSize.iWidth);
+ rectToClear.iBr.iX = screenPos.iPoint.iX + (endXPos * glyphSize.iWidth);
+ TRgb backgroundColor = MapColor(attributes.iAttributes, attributes.iBackgroundColor);
+ aDrawTo.SetBrushColor(backgroundColor);
+ aDrawTo.Clear(rectToClear);
+
+ // Check if we're blinking.
+ TRgb foregroundColor = MapColor(attributes.iAttributes, attributes.iForegroundColor);
+ if ((attributes.iAttributes & ConsoleAttributes::EBlink) && iBlinkOn)
+ {
+ foregroundColor = backgroundColor;
+ }
+
+ // Draw any non-white-space characters in the appropriate foreground color.
+ for (TInt i = startXPos; i < endXPos; ++i)
+ {
+ TUint16 c = At(i);
+ if (c != ' ')
+ {
+ const_cast<CConsoleFont&>(iFont).DrawChar(c, aDrawTo, TPoint(screenPos.iPoint.iX + (i * glyphSize.iWidth), screenPos.iPoint.iY), foregroundColor);
+ }
+ if (attributes.iAttributes & ConsoleAttributes::EUnderscore)
+ {
+ const_cast<CConsoleFont&>(iFont).DrawChar('_', aDrawTo, TPoint(screenPos.iPoint.iX + (i * glyphSize.iWidth), screenPos.iPoint.iY), foregroundColor);
+ }
+ }
+
+ if (attributes.iAttributes & ConsoleAttributes::EBlink)
+ {
+ iControl.StartBlinking();
+ }
+ }
+ }
+
+TBool CConsoleLine::NeedToBlink(TBool aBlinkOn)
+ {
+ TBool needToBlink(EFalse);
+ const TInt numAttributeBlocks = iAttributeMap.NumberOfBlocks();
+ for (TInt i = 0; i < numAttributeBlocks; ++i)
+ {
+ TInt startXPos = 0;
+ TInt endXPos = 0;
+ ConsoleAttributes::TAttributes attributes(ConsoleAttributes::ENone);
+ iAttributeMap.GetBlock(i, iWidth, startXPos, endXPos, attributes);
+ if (attributes.iAttributes & ConsoleAttributes::EBlink)
+ {
+ needToBlink = ETrue;
+ iBlinkOn = aBlinkOn;
+ break;
+ }
+ }
+ return needToBlink;
+ }
+
+TUint16 CConsoleLine::At(TInt aPos) const
+ {
+ __ASSERT_ALWAYS((aPos < iWidth)&&(aPos>=0), User::Invariant());
+ if (aPos < iText.Length())
+ {
+ return iText[aPos];
+ }
+ else
+ {
+ return ' ';
+ }
+ }
+
+CConsoleLine::CConsoleLine(CConsoleControl& aControl, const CConsoleFont& aFont)
+ : iControl(aControl), iFont(aFont)
+ {
+ }
+
+void CConsoleLine::ConstructL(TInt aWidth)
+ {
+ iText.CreateL(aWidth);
+ iWidth = aWidth;
+ }
+
+//______________________________________________________________________________
+// TConsoleCursor
+TConsoleCursor::TConsoleCursor(CConsoleControl& aOwner)
+ : iOwner(aOwner)
+ {
+ iTextCursor.iType = TTextCursor::ETypeRectangle;
+ iTextCursor.iAscent = 0;
+ iTextCursor.iColor = KRgbWhite;
+ }
+
+void TConsoleCursor::SetFont(const CConsoleFont& aFont)
+ {
+ iGlyphSize = aFont.GlyphSize();
+ iTextCursor.iWidth = iGlyphSize.iWidth;
+ }
+
+TConsCursorPosition TConsoleCursor::Position() const
+ {
+ return TConsCursorPosition(iOwner, iPosition);
+ }
+
+void TConsoleCursor::SetPosAbs(TConsCursorPosition aPos)
+ {
+ iPosition = aPos.iPoint;
+ BoundsCheck();
+ }
+
+void TConsoleCursor::SetPosRel(TConsCursorPosition aPos)
+ {
+ iPosition += aPos.iPoint;
+ BoundsCheck();
+ }
+
+void TConsoleCursor::SetHeight(TInt aPercentage)
+ {
+ aPercentage = Max(0, Min(100, aPercentage));
+ TReal height = ((TReal)iGlyphSize.iHeight * (TReal)aPercentage) / 100.0;
+ TReal roundedHeight;
+ Math::Round(roundedHeight, height, 0);
+ iTextCursor.iHeight = (TInt)roundedHeight;
+ // make sure the cursor is always visible if the percentage is non-zero.
+ if ((iTextCursor.iHeight==0) && (aPercentage!=0)) iTextCursor.iHeight = 1;
+ iTextCursor.iAscent = 0;
+ iTextCursorOffset = iGlyphSize.iHeight - iTextCursor.iHeight;
+ }
+
+void TConsoleCursor::Update()
+ {
+ if (iOwner.IsFocused() && !iOwner.IsNonFocusing())
+ {
+ TViewPosition viewPos = Position();
+ TPoint cursorPosPixels;
+ cursorPosPixels.iX = viewPos.iPoint.iX * iGlyphSize.iWidth;
+ cursorPosPixels.iY = ((viewPos.iPoint.iY) * iGlyphSize.iHeight) + iTextCursorOffset;
+ /*if (iOwner.Rect().Contains(cursorPosPixels))
+ {*/
+ if (iOwner.DrawableWindow())
+ {
+ CCoeEnv::Static()->RootWin().SetTextCursor(*iOwner.DrawableWindow(), cursorPosPixels, iTextCursor);
+ }
+ /* }
+ else
+ {
+ Hide();
+ }*/
+ }
+ }
+
+void TConsoleCursor::Hide()
+ {
+ CCoeEnv::Static()->RootWin().CancelTextCursor();
+ }
+
+void TConsoleCursor::BoundsCheck()
+ {
+ iPosition.iX = Max(0, iPosition.iX);
+ iPosition.iY = Max(0, iPosition.iY);
+ iPosition.iX = Min(iOwner.ScreenSize().iWidth-1, iPosition.iX);
+ iPosition.iY = Min(iOwner.ScreenSize().iHeight-1, iPosition.iY);
+ }
+
+void TConsoleCursor::operator++(int)
+ {
+ (*this)+=1;
+ }
+
+void TConsoleCursor::operator--(int)
+ {
+ (*this)-=1;
+ }
+
+void TConsoleCursor::operator+=(TUint aHowMuch)
+ {
+ TSize consSize(iOwner.ScreenSize());
+ while (aHowMuch)
+ {
+ TInt len = Min(consSize.iWidth - iPosition.iX, aHowMuch);
+ iPosition.iX += len;
+ aHowMuch -= len;
+
+ if (iPosition.iX == consSize.iWidth)
+ {
+ Down();
+ iPosition.iX = 0;
+ }
+ }
+ }
+
+void TConsoleCursor::operator-=(TUint aHowMuch)
+ {
+ TSize consSize(iOwner.ScreenSize());
+ while (aHowMuch)
+ {
+ if (iPosition.iX == 0)
+ {
+ Up();
+ iPosition.iX = consSize.iWidth;
+ }
+
+ TInt len = Min(iPosition.iX, aHowMuch);
+ iPosition.iX -= len;
+ aHowMuch -= len;
+ }
+
+ }
+
+void TConsoleCursor::Down()
+ {
+ iPosition.iY++;
+ if (iPosition.iY >= iOwner.ScreenSize().iHeight)
+ {
+ iPosition.iY--;
+ iOwner.CursorWindowScrollDown();
+ }
+ }
+
+void TConsoleCursor::Up()
+ {
+ iPosition.iY--;
+ BoundsCheck();
+ }
+
+//______________________________________________________________________________
+// CGuiConsole
+EXPORT_C CGuiConsole::CGuiConsole(CConsoleControl& aControl)
+ : iControl(aControl), iRefCount(1)
+ {
+ }
+
+EXPORT_C CConsoleControl& CGuiConsole::Control()
+ {
+ return iControl;
+ }
+
+EXPORT_C TInt CGuiConsole::Create(const TDesC &aTitle, TSize)
+ {
+ iControl.SetTitle(aTitle);
+ return KErrNone;
+ }
+
+EXPORT_C void CGuiConsole::Read(TRequestStatus &aStatus)
+ {
+ if (iReadStatus || iReader)
+ {
+ TRequestStatus* stat = &aStatus;
+ User::RequestComplete(stat, KErrInUse);
+ }
+ else
+ {
+ iReadStatus = &aStatus;
+ iControl.Read(*this);
+ }
+ }
+
+EXPORT_C void CGuiConsole::ReadCancel()
+ {
+ if (iReadStatus)
+ {
+ User::RequestComplete(iReadStatus, KErrCancel);
+ iControl.ReadCancel();
+ }
+ else if (iReader)
+ {
+ iReader->ReadComplete(KErrCancel);
+ iReader = NULL;
+ iControl.ReadCancel();
+ }
+ }
+
+EXPORT_C void CGuiConsole::Write(const TDesC &aDes)
+ {
+ iControl.Write(aDes);
+ }
+
+EXPORT_C TPoint CGuiConsole::CursorPos() const
+ {
+ return iControl.CursorPos();
+ }
+
+EXPORT_C void CGuiConsole::SetCursorPosAbs(const TPoint &aPoint)
+ {
+ iControl.SetCursorPosAbs(aPoint);
+ }
+
+EXPORT_C void CGuiConsole::SetCursorPosRel(const TPoint &aPoint)
+ {
+ iControl.SetCursorPosRel(aPoint);
+ }
+
+EXPORT_C void CGuiConsole::SetCursorHeight(TInt aPercentage)
+ {
+ iControl.SetCursorHeight(aPercentage);
+ }
+
+EXPORT_C void CGuiConsole::SetTitle(const TDesC &aTitle)
+ {
+ iControl.SetTitle(aTitle);
+ }
+
+EXPORT_C void CGuiConsole::ClearScreen()
+ {
+ iControl.ClearScreen();
+ }
+
+EXPORT_C void CGuiConsole::ClearToEndOfLine()
+ {
+ iControl.ClearToEndOfLine();
+ }
+
+EXPORT_C TSize CGuiConsole::ScreenSize() const
+ {
+ return iControl.ScreenSize();
+ }
+
+
+EXPORT_C TKeyCode CGuiConsole::KeyCode() const
+ {
+ return iControl.KeyCode();
+ }
+
+
+EXPORT_C TUint CGuiConsole::KeyModifiers() const
+ {
+ return iControl.KeyModifiers();
+ }
+
+EXPORT_C TInt CGuiConsole::Extension_(TUint aExtensionId, TAny*&, TAny* a1)
+ {
+ if (aExtensionId == ConsoleAttributes::KSetConsoleAttributesExtension)
+ {
+ ConsoleAttributes::TAttributes* attributes = (ConsoleAttributes::TAttributes*)a1;
+ return iControl.SetAttributes(attributes->iAttributes, attributes->iForegroundColor, attributes->iBackgroundColor);
+ }
+ return KErrNotSupported;
+ }
+
+void CGuiConsole::ReadComplete(TInt aStatus)
+ {
+ if (iReadStatus)
+ {
+ User::RequestComplete(iReadStatus, aStatus);
+ }
+ if (iReader)
+ {
+ CConsoleProxySession* reader = iReader;
+ iReader = NULL;
+ reader->ReadComplete(aStatus);
+ }
+ }
+
+void CGuiConsole::Open()
+ {
+ ++iRefCount;
+ }
+
+void CGuiConsole::Close()
+ {
+ --iRefCount;
+ if (iRefCount==0)
+ {
+ delete this;
+ }
+ }
+
+CConsoleBase* CGuiConsole::Console()
+ {
+ return this;
+ }
+
+void CGuiConsole::Read(CConsoleProxySession& aSession)
+ {
+ if (iReader || iReadStatus)
+ {
+ aSession.ReadComplete(KErrInUse);
+ }
+ else
+ {
+ iReader = &aSession;
+ iControl.Read(*this);
+ }
+ }
+
+CGuiConsole::~CGuiConsole()
+ {
+ iControl.Closed();
+ }
+
+//______________________________________________________________________________
+// TBufferPosition
+TBufferPosition::TBufferPosition(const CConsoleControl& aConsole, TPoint aPosition)
+ : iConsole(aConsole), iPoint(aPosition)
+ {
+ }
+
+TBufferPosition::TBufferPosition(const CConsoleControl& aConsole, TInt aX, TInt aY)
+ : iConsole(aConsole), iPoint(aX, aY)
+ {
+ }
+
+TBufferPosition::TBufferPosition(const TConsCursorPosition& aCursorPosition)
+ : iConsole(aCursorPosition.iConsole)
+ , iPoint(aCursorPosition.iPoint + aCursorPosition.iConsole.CursorWindowPosition())
+ {
+ }
+
+TBufferPosition::TBufferPosition(const TViewPosition& aViewPosition)
+ : iConsole(aViewPosition.iConsole)
+ , iPoint(aViewPosition.iPoint + aViewPosition.iConsole.ViewPosition())
+ {
+ }
+
+
+
+//______________________________________________________________________________
+// TConsCursorPosition
+TConsCursorPosition::TConsCursorPosition(const CConsoleControl& aConsole, TPoint aPosition)
+ : iConsole(aConsole), iPoint(aPosition)
+ {
+ }
+
+TConsCursorPosition::TConsCursorPosition(const CConsoleControl& aConsole, TInt aX, TInt aY)
+ : iConsole(aConsole), iPoint(aX, aY)
+ {
+ }
+
+TConsCursorPosition::TConsCursorPosition(const TBufferPosition& aBufferPosition)
+ : iConsole(aBufferPosition.iConsole)
+ , iPoint(aBufferPosition.iPoint - aBufferPosition.iConsole.CursorWindowPosition())
+ {
+ }
+
+TConsCursorPosition::TConsCursorPosition(const TViewPosition& aViewPosition)
+ : iConsole(aViewPosition.iConsole)
+ , iPoint(aViewPosition.iPoint + aViewPosition.iConsole.ViewPosition() - aViewPosition.iConsole.CursorWindowPosition())
+ {
+ }
+
+
+
+//______________________________________________________________________________
+// TViewPosition
+TViewPosition::TViewPosition(const CConsoleControl& aConsole, TPoint aPosition)
+ : iConsole(aConsole), iPoint(aPosition)
+ {
+ }
+
+TViewPosition::TViewPosition(const CConsoleControl& aConsole, TInt aX, TInt aY)
+ : iConsole(aConsole), iPoint(aX, aY)
+ {
+ }
+
+TViewPosition::TViewPosition(const TConsCursorPosition& aCursorPosition)
+ : iConsole(aCursorPosition.iConsole)
+ , iPoint(aCursorPosition.iPoint + aCursorPosition.iConsole.CursorWindowPosition() - aCursorPosition.iConsole.ViewPosition())
+ {
+ }
+
+TViewPosition::TViewPosition(const TBufferPosition& aBufferPosition)
+ : iConsole(aBufferPosition.iConsole)
+ , iPoint(aBufferPosition.iPoint - aBufferPosition.iConsole.ViewPosition())
+ {
+ }
+
+//______________________________________________________________________________
+// TScreenPosition
+TScreenPosition::TScreenPosition(const CConsoleControl& aConsole, TPoint aPosition)
+ : iConsole(aConsole), iPoint(aPosition)
+ {
+ }
+
+TScreenPosition::TScreenPosition(const CConsoleControl& aConsole, TInt aX, TInt aY)
+ : iConsole(aConsole), iPoint(aX, aY)
+ {
+ }
+
+TScreenPosition::TScreenPosition(const TViewPosition& aViewPosition)
+ : iConsole(aViewPosition.iConsole)
+ , iPoint(aViewPosition.iPoint.iX * aViewPosition.iConsole.GlyphSize().iWidth, aViewPosition.iPoint.iY * aViewPosition.iConsole.GlyphSize().iHeight)
+ {
+ }
+
+//______________________________________________________________________________
+// RAttributeMap
+
+RAttributeMap::RAttributeMap()
+ : iAttributes(KAttributeMapGranularity, _FOFF(TAttributes, iPosition))
+ {
+ }
+
+void RAttributeMap::Close()
+ {
+ iAttributes.Close();
+ }
+
+void RAttributeMap::Reset()
+ {
+ iAttributes.Reset();
+ }
+
+void RAttributeMap::AddL(TInt aPosition, TInt aLineWidth, const ConsoleAttributes::TAttributes& aAttributes)
+ {
+ // Take a copy of the attributes array to make cleanup easier.
+ RArray<TAttributes> attributes;
+ CleanupClosePushL(attributes);
+ const TInt numAttributes = iAttributes.Count();
+ for (TInt i = 0; i < numAttributes; ++i)
+ {
+ attributes.AppendL(iAttributes[i]);
+ }
+
+ if (attributes.Count() == 0)
+ {
+ // This is the first set of attributes to be added. Add a default set before them.
+ attributes.AppendL(TAttributes(0, DefaultAttributes()));
+ }
+
+ TAttributes attr(aPosition, aAttributes);
+ TInt pos;
+ TInt err = attributes.FindInSignedKeyOrder(attr, pos);
+ if (err == KErrNone)
+ {
+ // Attribute already exists at this position - replace.
+ attributes[pos] = attr;
+ }
+ else
+ {
+ // No attribute found at aPosition.
+ // pos is set to the index _after_ aPosition. This must be at least 1 because the first slot in the array is always taken with defaults or something else.
+ // Set pos to the index _before_ aPosition.
+ --pos;
+
+ // Check earlier attributes to see if they match.
+ if (!(attributes[pos] == attr))
+ {
+ // No match - insert new attributes.
+ attributes.InsertInSignedKeyOrderL(attr);
+
+ // Get the position of the newly inserted attributes.
+ attributes.FindInSignedKeyOrder(attr, pos);
+ }
+ }
+
+ const TAttributes& newAttributes = attributes[pos];
+ if ((pos == (attributes.Count() - 1)) && (newAttributes.iPosition < (aLineWidth - 1)) && !(newAttributes == TAttributes(0, DefaultAttributes())))
+ {
+ // New attributes are the last in the list, and not at the end of the line and not defaults.
+ // Add another set of defaults after them.
+ attributes.AppendL(TAttributes(newAttributes.iPosition + 1, DefaultAttributes()));
+ }
+
+ iAttributes.Close();
+ iAttributes = attributes;
+ CleanupStack::Pop(&attributes);
+ }
+
+void RAttributeMap::RemoveFrom(TInt aPosition)
+ {
+ for (TInt i = (iAttributes.Count() - 1); i >= 0; --i)
+ {
+ if (iAttributes[i].iPosition >= aPosition)
+ {
+ iAttributes.Remove(i);
+ }
+ }
+ }
+
+TInt RAttributeMap::NumberOfBlocks() const
+ {
+ if (iAttributes.Count() == 0)
+ {
+ return 1; // If no attributes have been added, give the entire line an implict default set of attributes.
+ }
+ return iAttributes.Count();
+ }
+
+void RAttributeMap::GetBlock(TInt aIndex, TInt aLineWidth, TInt& aStartPosition, TInt& aEndPosition, ConsoleAttributes::TAttributes& aAttributes) const
+ {
+ if (iAttributes.Count() == 0)
+ {
+ ASSERT(aIndex == 0);
+ aStartPosition = 0;
+ aEndPosition = aLineWidth;
+ aAttributes = DefaultAttributes();
+ }
+ else
+ {
+ const TAttributes& attributes = iAttributes[aIndex];
+ aAttributes = attributes.iAttributes;
+ aStartPosition = attributes.iPosition;
+
+ if ((iAttributes.Count() == 1) || (aIndex == (iAttributes.Count() - 1)))
+ {
+ aEndPosition = aLineWidth;
+ }
+ else
+ {
+ aEndPosition = iAttributes[aIndex + 1].iPosition;
+ }
+ }
+ }
+
+RAttributeMap::TAttributes::TAttributes(TInt aPosition, const ConsoleAttributes::TAttributes& aAttributes)
+ : iPosition(aPosition), iAttributes(aAttributes)
+ {
+ }
+
+TBool RAttributeMap::TAttributes::operator==(const TAttributes& aAttributes) const
+ {
+ // Note, intentionally ignoring iPosition so ensure that existing attribute block are extended where possible.
+ return ((iAttributes.iAttributes == aAttributes.iAttributes.iAttributes) &&
+ (iAttributes.iForegroundColor == aAttributes.iAttributes.iForegroundColor) &&
+ (iAttributes.iBackgroundColor == aAttributes.iAttributes.iBackgroundColor));
+ }