/*************************************************************************
	Handler for when character (printable keys) are typed
*************************************************************************/
void MultiLineEditbox::onCharacter(KeyEventArgs& e)
{
	// base class processing
	Window::onCharacter(e);

	// only need to take notice if we have focus
	if (hasInputFocus() && !isReadOnly() && getFont()->isCodepointAvailable(e.codepoint))
	{
		// erase selected text
		eraseSelectedText();

		// if there is room
		if (d_text.length() - 1 < d_maxTextLen)
		{
			d_text.insert(getCaratIndex(), 1, e.codepoint);
			d_caratPos++;

			WindowEventArgs args(this);
			onTextChanged(args);
		}
		else
		{
			// Trigger text box full event
			WindowEventArgs args(this);
			onEditboxFullEvent(args);
		}

	}

	e.handled = true;
}
/*************************************************************************
	Processing to move carat one word left
*************************************************************************/
void MultiLineEditbox::handleWordLeft(uint sysKeys)
{
	if (d_caratPos > 0)
	{
		setCaratIndex(TextUtils::getWordStartIdx(d_text, getCaratIndex()));
	}

	if (sysKeys & Shift)
	{
		setSelection(d_caratPos, d_dragAnchorIdx);	
	}
	else
	{
		clearSelection();
	}

}
/*************************************************************************
	Processing to move carat one word right
*************************************************************************/
void MultiLineEditbox::handleWordRight(UINT sysKeys)
{
	if (d_caratPos < d_text.length() - 1)
	{
		setCaratIndex(TextUtils::getNextWordStartIdx(d_text, getCaratIndex()));
	}

	if (sysKeys & Shift)
	{
		setSelection(d_caratPos, d_dragAnchorIdx);	
	}
	else
	{
		clearSelection();
	}

}
/*************************************************************************
	Processing for Delete key
*************************************************************************/
void MultiLineEditbox::handleDelete(void)
{
	if (!isReadOnly())
	{
		if (getSelectionLength() != 0)
		{
			eraseSelectedText();
		}
		else if (getCaratIndex() < d_text.length() - 1)
		{
			d_text.erase(d_caratPos, 1);
			ensureCaratIsVisible();

			WindowEventArgs args(this);
			onTextChanged(args);
		}

	}

}
/*************************************************************************
	Processing to insert a new line / paragraph.
*************************************************************************/
void MultiLineEditbox::handleNewLine(uint sysKeys)
{
	if (!isReadOnly())
	{
		// erase selected text
		eraseSelectedText();

		// if there is room
		if (d_text.length() - 1 < d_maxTextLen)
		{
			d_text.insert(getCaratIndex(), 1, 0x0a);
			d_caratPos++;

			WindowEventArgs args(this);
			onTextChanged(args);
		}

	}

}
/*************************************************************************
	Handler for when text is programmatically changed.
*************************************************************************/
void MultiLineEditbox::onTextChanged(WindowEventArgs& e)
{
    // ensure last character is a new line
    if ((d_text.length() == 0) || (d_text[d_text.length() - 1] != '\n'))
        d_text.append(1, '\n');

    // base class processing
    Window::onTextChanged(e);

    // clear selection
    clearSelection();
    // layout new text
    formatText();
    // layout child windows (scrollbars) since text layout may have changed
    performChildWindowLayout();
    // ensure carat is still within the text
    setCaratIndex(getCaratIndex());
    // ensure carat is visible
    // NB: this will already have been called at least once, but since we
    // may have changed the formatting of the text, it needs to be called again.
    ensureCaratIsVisible();

    e.handled = true;
}
Exemple #7
0
    void FalagardEditbox::populateRenderCache()
    {
        const StateImagery* imagery;

        // draw container etc
        // get WidgetLookFeel for the assigned look.
        const WidgetLookFeel& wlf = WidgetLookManager::getSingleton().getWidgetLook(d_lookName);
        // try and get imagery for the approprite state.
        imagery = &wlf.getStateImagery(isDisabled() ? "Disabled" : (isReadOnly() ? "ReadOnly" : "Enabled"));

        // peform the rendering operation for the container.
        imagery->render(*this);

        // get destination area for text
        const Rect textArea(wlf.getNamedArea("TextArea").getArea().getPixelRect(*this));

        //
        // Required preliminary work for text rendering operations
        //
        const Font* font = getFont();

        // no font == no more rendering
        if (!font)
            return;

        // This will point to the final string to be used for rendering.  Useful because it means we
        // do not have to have duplicate code or be copying d_text for handling masked/unmasked text.
        String* editText;

        // Create a 'masked' version of the string if needed.
        String maskedText;
        if (isTextMasked())
        {
            maskedText.insert(0, d_text.length(), getMaskCodePoint());
            editText = &maskedText;
        }
        // text not masked to editText will be the windows d_text String.
        else
        {
            editText = &d_text;
        }

        // calculate best position to render text to ensure carat is always visible
        float textOffset;
        float extentToCarat = font->getTextExtent(editText->substr(0, getCaratIndex()));

        // get carat imagery
        const ImagerySection& caratImagery = wlf.getImagerySection("Carat");
        // store carat width
        float caratWidth = caratImagery.getBoundingRect(*this, textArea).getWidth();

        // if box is inactive
        if (!hasInputFocus())
        {
            textOffset = d_lastTextOffset;
        }
        // if carat is to the left of the box
        else if ((d_lastTextOffset + extentToCarat) < 0)
        {
            textOffset = -extentToCarat;
        }
        // if carat is off to the right.
        else if ((d_lastTextOffset + extentToCarat) >= (textArea.getWidth() - caratWidth))
        {
            textOffset = textArea.getWidth() - extentToCarat - caratWidth;
        }
        // else carat is already within the box
        else
        {
            textOffset = d_lastTextOffset;
        }

        ColourRect colours;
        float alpha_comp = getEffectiveAlpha();

        //
        // Draw label text
        //
        // setup initial rect for text formatting
        Rect text_part_rect(textArea);
        // allow for scroll position
        text_part_rect.d_left += textOffset;
        // centre text vertically within the defined text area
        text_part_rect.d_top += (textArea.getHeight() - font->getLineSpacing()) * 0.5f;

        // draw pre-highlight text
        String sect = editText->substr(0, getSelectionStartIndex());
        colours.setColours(d_normalTextColour);
        colours.modulateAlpha(alpha_comp);
        d_renderCache.cacheText(sect, font, LeftAligned, text_part_rect, 0, colours, &textArea);

        // adjust rect for next section
        text_part_rect.d_left += font->getTextExtent(sect);

        // draw highlight text
        sect = editText->substr(getSelectionStartIndex(), getSelectionLength());
        colours.setColours(d_selectTextColour);
        colours.modulateAlpha(alpha_comp);
        d_renderCache.cacheText(sect, font, LeftAligned, text_part_rect, 0, colours, &textArea);

        // adjust rect for next section
        text_part_rect.d_left += font->getTextExtent(sect);

        // draw post-highlight text
        sect = editText->substr(getSelectionEndIndex());
        colours.setColours(d_normalTextColour);
        colours.modulateAlpha(alpha_comp);
        d_renderCache.cacheText(sect, font, LeftAligned, text_part_rect, 0, colours, &textArea);

        // remember this for next time.
        d_lastTextOffset = textOffset;

        // see if the editbox is active or inactive.
        bool active = (!isReadOnly()) && hasInputFocus();

        //
        // Render selection imagery.
        //
        if (getSelectionLength() != 0)
        {
            // calculate required start and end offsets of selection imagery.
            float selStartOffset = font->getTextExtent(editText->substr(0, getSelectionStartIndex()));
            float selEndOffset   = font->getTextExtent(editText->substr(0, getSelectionEndIndex()));

            // calculate area for selection imagery.
            Rect hlarea(textArea);
            hlarea.d_left += textOffset + selStartOffset;
            hlarea.d_right = hlarea.d_left + (selEndOffset - selStartOffset);

            // render the selection imagery.
            wlf.getStateImagery(active ? "ActiveSelection" : "InactiveSelection").render(*this, hlarea, 0, &textArea);
        }

        //
        // Render carat
        //
        if (active)
        {
            Rect caratRect(textArea);
            caratRect.d_left += extentToCarat + textOffset;

            caratImagery.render(*this, caratRect, 0, 0, &textArea);
        }
    }
/*************************************************************************
	Handler for when non-printable keys are typed.
*************************************************************************/
void MultiLineEditbox::onKeyDown(KeyEventArgs& e)
{
	// base class processing
	Window::onKeyDown(e);

	if (hasInputFocus() && !isReadOnly())
	{
		WindowEventArgs args(this);
		switch (e.scancode)
		{
		case Key::LeftShift:
		case Key::RightShift:
			if (getSelectionLength() == 0)
			{
				d_dragAnchorIdx = getCaratIndex();
			}
			break;

		case Key::Backspace:
			handleBackspace();
			break;

		case Key::Delete:
			handleDelete();
			break;

		case Key::Return:
		case Key::NumpadEnter:
			handleNewLine(e.sysKeys);
			break;

		case Key::ArrowLeft:
			if (e.sysKeys & Control)
			{
				handleWordLeft(e.sysKeys);
			}
			else
			{
				handleCharLeft(e.sysKeys);
			}
			break;

		case Key::ArrowRight:
			if (e.sysKeys & Control)
			{
				handleWordRight(e.sysKeys);
			}
			else
			{
				handleCharRight(e.sysKeys);
			}
			break;

		case Key::ArrowUp:
			handleLineUp(e.sysKeys);
			break;

		case Key::ArrowDown:
			handleLineDown(e.sysKeys);
			break;

		case Key::Home:
			if (e.sysKeys & Control)
			{
				handleDocHome(e.sysKeys);
			}
			else
			{
				handleLineHome(e.sysKeys);
			}
			break;

		case Key::End:
			if (e.sysKeys & Control)
			{
				handleDocEnd(e.sysKeys);
			}
			else
			{
				handleLineEnd(e.sysKeys);
			}
			break;

        // default case is now to leave event as (possibly) unhandled.
        default:
            return;
		}

		e.handled = true;
	}

}