private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUiState state, object stateLock)
        {
            timedAction.Reset(() =>
            {
                lock (stateLock)
                {
                    // The blinker is on half of the time and events such as input
                    // changes can reset the blinker.
                    state.TextBoxBlinkCounter = (state.TextBoxBlinkCounter + 1) % (2 * SoftwareKeyboardRendererBase.TextBoxBlinkThreshold);

                    // Tell the render thread there is something new to render.
                    Monitor.PulseAll(stateLock);
                }
            }, TextBoxBlinkSleepMilliseconds);
        }
        private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock)
        {
            SoftwareKeyboardUiState internalState = new SoftwareKeyboardUiState();

            bool canCreateSurface = false;
            bool needsUpdate      = true;

            timedAction.Reset(() =>
            {
                lock (stateLock)
                {
                    if (!Monitor.Wait(stateLock, RendererWaitTimeoutMilliseconds))
                    {
                        return;
                    }

                    needsUpdate  = UpdateStateField(ref state.InputText, ref internalState.InputText);
                    needsUpdate |= UpdateStateField(ref state.CursorBegin, ref internalState.CursorBegin);
                    needsUpdate |= UpdateStateField(ref state.CursorEnd, ref internalState.CursorEnd);
                    needsUpdate |= UpdateStateField(ref state.AcceptPressed, ref internalState.AcceptPressed);
                    needsUpdate |= UpdateStateField(ref state.CancelPressed, ref internalState.CancelPressed);
                    needsUpdate |= UpdateStateField(ref state.OverwriteMode, ref internalState.OverwriteMode);
                    needsUpdate |= UpdateStateField(ref state.TypingEnabled, ref internalState.TypingEnabled);
                    needsUpdate |= UpdateStateField(ref state.ControllerEnabled, ref internalState.ControllerEnabled);
                    needsUpdate |= UpdateStateField(ref state.TextBoxBlinkCounter, ref internalState.TextBoxBlinkCounter);

                    canCreateSurface = state.SurfaceInfo != null && internalState.SurfaceInfo == null;

                    if (canCreateSurface)
                    {
                        internalState.SurfaceInfo = state.SurfaceInfo;
                    }
                }

                if (canCreateSurface)
                {
                    renderer.CreateSurface(internalState.SurfaceInfo);
                }

                if (needsUpdate)
                {
                    renderer.DrawMutableElements(internalState);
                    renderer.CopyImageToBuffer();
                    needsUpdate = false;
                }
            });
        }
示例#3
0
        public void DrawMutableElements(SoftwareKeyboardUiState state)
        {
            if (_surface == null)
            {
                return;
            }

            _surface.Mutate(context =>
            {
                var messageRectangle      = MeasureString(MessageText, _messageFont);
                float messagePositionX    = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.X;
                float messagePositionY    = _messagePositionY - messageRectangle.Y;
                var messagePosition       = new PointF(messagePositionX, messagePositionY);
                var messageBoundRectangle = new RectangleF(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height);

                SetGraphicsOptions(context);

                context.Fill(_panelBrush, messageBoundRectangle);

                context.DrawText(MessageText, _messageFont, _textNormalColor, messagePosition);

                if (!state.TypingEnabled)
                {
                    // Just draw a semi-transparent rectangle on top to fade the component with the background.
                    // TODO (caian): This will not work if one decides to add make background semi-transparent as well.

                    context.Fill(_disabledBrush, messageBoundRectangle);
                }

                DrawTextBox(context, state);

                float halfWidth = _panelRectangle.Width / 2;
                float buttonsY  = _panelRectangle.Y + 185;

                PointF acceptButtonPosition  = new PointF(halfWidth - 180, buttonsY);
                PointF cancelButtonPosition  = new PointF(halfWidth, buttonsY);
                PointF disableButtonPosition = new PointF(halfWidth + 180, buttonsY);

                DrawPadButton(context, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled);
                DrawPadButton(context, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled);
            });
        }
示例#4
0
        private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUiState state)
        {
            var inputTextRectangle = MeasureString(state.InputText, _inputTextFont);

            float boxWidth  = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.X + 8));
            float boxHeight = 32;
            float boxY      = _panelRectangle.Y + 110;
            float boxX      = (int)((_panelRectangle.Width - boxWidth) / 2);

            RectangleF boxRectangle = new RectangleF(boxX, boxY, boxWidth, boxHeight);

            RectangleF boundRectangle = new RectangleF(_panelRectangle.X, boxY - _textBoxOutlineWidth,
                                                       _panelRectangle.Width, boxHeight + 2 * _textBoxOutlineWidth);

            context.Fill(_panelBrush, boundRectangle);

            context.Draw(_textBoxOutlinePen, boxRectangle);

            float inputTextX = (_panelRectangle.Width - inputTextRectangle.Width) / 2 - inputTextRectangle.X;
            float inputTextY = boxY + 5;

            var inputTextPosition = new PointF(inputTextX, inputTextY);

            context.DrawText(state.InputText, _inputTextFont, _textNormalColor, inputTextPosition);

            // Draw the cursor on top of the text and redraw the text with a different color if necessary.

            Color  cursorTextColor;
            IBrush cursorBrush;
            Pen    cursorPen;

            float cursorPositionYTop    = inputTextY + 1;
            float cursorPositionYBottom = cursorPositionYTop + _inputTextFontSize + 1;
            float cursorPositionXLeft;
            float cursorPositionXRight;

            bool cursorVisible = false;

            if (state.CursorBegin != state.CursorEnd)
            {
                Debug.Assert(state.InputText.Length > 0);

                cursorTextColor = _textSelectedColor;
                cursorBrush     = _selectionBoxBrush;
                cursorPen       = _selectionBoxPen;

                string textUntilBegin = state.InputText.Substring(0, state.CursorBegin);
                string textUntilEnd   = state.InputText.Substring(0, state.CursorEnd);

                var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont);
                var selectionEndRectangle   = MeasureString(textUntilEnd, _inputTextFont);

                cursorVisible        = true;
                cursorPositionXLeft  = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.X;
                cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.X;
            }
            else
            {
                cursorTextColor = _textOverCursorColor;
                cursorBrush     = _cursorBrush;
                cursorPen       = _cursorPen;

                if (state.TextBoxBlinkCounter < TextBoxBlinkThreshold)
                {
                    // Show the blinking cursor.

                    int    cursorBegin         = Math.Min(state.InputText.Length, state.CursorBegin);
                    string textUntilCursor     = state.InputText.Substring(0, cursorBegin);
                    var    cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);

                    cursorVisible       = true;
                    cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;

                    if (state.OverwriteMode)
                    {
                        // The blinking cursor is in overwrite mode so it takes the size of a character.

                        if (state.CursorBegin < state.InputText.Length)
                        {
                            textUntilCursor      = state.InputText.Substring(0, cursorBegin + 1);
                            cursorTextRectangle  = MeasureString(textUntilCursor, _inputTextFont);
                            cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
                        }
                        else
                        {
                            cursorPositionXRight = cursorPositionXLeft + _inputTextFontSize / 2;
                        }
                    }
                    else
                    {
                        // The blinking cursor is in insert mode so it is only a line.
                        cursorPositionXRight = cursorPositionXLeft;
                    }
                }
                else
                {
                    cursorPositionXLeft  = inputTextX;
                    cursorPositionXRight = inputTextX;
                }
            }

            if (state.TypingEnabled && cursorVisible)
            {
                float cursorWidth  = cursorPositionXRight - cursorPositionXLeft;
                float cursorHeight = cursorPositionYBottom - cursorPositionYTop;

                if (cursorWidth == 0)
                {
                    PointF[] points = new PointF[]
                    {
                        new PointF(cursorPositionXLeft, cursorPositionYTop),
                        new PointF(cursorPositionXLeft, cursorPositionYBottom),
                    };

                    context.DrawLines(cursorPen, points);
                }
                else
                {
                    var cursorRectangle = new RectangleF(cursorPositionXLeft, cursorPositionYTop, cursorWidth, cursorHeight);

                    context.Draw(cursorPen, cursorRectangle);
                    context.Fill(cursorBrush, cursorRectangle);

                    Image <Argb32> textOverCursor = new Image <Argb32>((int)cursorRectangle.Width, (int)cursorRectangle.Height);
                    textOverCursor.Mutate(context =>
                    {
                        var textRelativePosition = new PointF(inputTextPosition.X - cursorRectangle.X, inputTextPosition.Y - cursorRectangle.Y);
                        context.DrawText(state.InputText, _inputTextFont, cursorTextColor, textRelativePosition);
                    });

                    var cursorPosition = new Point((int)cursorRectangle.X, (int)cursorRectangle.Y);
                    context.DrawImage(textOverCursor, cursorPosition, 1);
                }
            }
            else if (!state.TypingEnabled)
            {
                // Just draw a semi-transparent rectangle on top to fade the component with the background.
                // TODO (caian): This will not work if one decides to add make background semi-transparent as well.

                context.Fill(_disabledBrush, boundRectangle);
            }
        }