Hello,
I'm curious if there is a widget that extends functionality of MultiLineEditBox to have undo/redo and maybe copy/paste? And if not, what is the best way to approach this?
Thanks.
Undo/Redo in MultiLineEditBox
Moderators: CEGUI MVP, CEGUI Team
I have implemented an OS-independent copy/paste mechanism using SCRAP
Please note that there is no way to get the currently "Active" widget from CEGUI, thus you need to implement "this->getActiveWidget()" yourself in some way.
Regarding undo/redo I have nothing for you.
Please note that there is no way to get the currently "Active" widget from CEGUI, thus you need to implement "this->getActiveWidget()" yourself in some way.
Code: Select all
/// Copies the currently selected text.
/** This function copies the currently selected text (maybe more to come ?)
* into the clipboard. It is system-independent !
*
* \param in_bDelete Whether to delete the copied object (cut) or not (copy)
*
* \return If successfull: ERR_OK
* \return If failed: An error code <0
*
* \author Pompei2
*/
int CFTSUI::copy(bool in_bDelete)
{
CEGUI::Window *activeWin = this->getActiveWidget();
CEGUI::String s;
const char *pszText = NULL;
if(activeWin == NULL)
return ERR_OK;
// Cancel, if the active widget is not an editable.
if(activeWin->getType() != "ArkanaLook/Editbox" &&
activeWin->getType() != "ArkanaLook/MultiLineEditbox")
return ERR_OK;
// Get the currently selected text from the widget.
// First, for normal editboxes:
if(activeWin->getType() == "ArkanaLook/Editbox") {
CEGUI::Editbox *e = (CEGUI::Editbox *)activeWin;
// No need to copy an empty selection.
if(e->getSelectionLength() == 0)
return ERR_OK;
s = CEGUI::String(e->getText(), e->getSelectionStartIndex(), e->getSelectionLength());
// Then, for normal MultiLineEditbox:
} else if(activeWin->getType() == "ArkanaLook/MultiLineEditbox") {
CEGUI::MultiLineEditbox *e = (CEGUI::MultiLineEditbox *)activeWin;
// No need to copy an empty selection.
if(e->getSelectionLength() == 0)
return ERR_OK;
s = CEGUI::String(e->getText(), e->getSelectionStartIndex(), e->getSelectionLength());
}
// To cut the text out, we use a little trick: simulate a keypress.
if(in_bDelete) {
CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Backspace);
}
pszText = s.c_str();
FTSMSG("%s", FTS_NOMSG, pszText);
put_scrap(T('T','E','X','T'), strlen(pszText), pszText);
return ERR_OK;
}
/// Copies the currently copied text into the current widget.
/** This function pastes the content of the clipboard into the currently selected
* object. Currently this works only for texts.
*
* \return If successfull: ERR_OK
* \return If failed: An error code <0
*
* \author Pompei2
*/
int CFTSUI::paste(void)
{
CEGUI::Window *activeWin = this->getActiveWidget();
char cNewline = ' ';
if(activeWin == NULL)
return ERR_OK;
// Cancel, if the active widget is not an editable.
if(activeWin->getType() == "ArkanaLook/Editbox")
cNewline = ' ';
else if(activeWin->getType() == "ArkanaLook/MultiLineEditbox")
cNewline = '\n';
else
return ERR_OK;
char *pszScrap = NULL;
int iScraplen = 0;
get_scrap(T('T','E','X','T'), &iScraplen, &pszScrap);
if(iScraplen == 0) {
FTSMSG("Text scrap is empty\n", FTS_NOMSG);
return ERR_OK;
}
// Convert mac newlines to unix newlines or spaces, whatever is needed.
for(int i = 0 ; i < iScraplen ; ++i) {
if(pszScrap[i] == '\r')
pszScrap[i] = cNewline;
}
// Build an CEGUI string based on this, to keep the accents and stuff.
CEGUI::String s((const CEGUI::utf8 *)pszScrap);
// And now inject each charachter, so it get placed into the editbox.
for(size_t i = 0 ; i < s.size() ; i++) {
if(s[i] == '\n') {
CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Return);
} else
CEGUI::System::getSingleton().injectChar(s[i]);
}
free(pszScrap);
return ERR_OK;
}
Regarding undo/redo I have nothing for you.
Pompei2 wrote:Please note that there is no way to get the currently "Active" widget from CEGUI, thus you need to implement "this->getActiveWidget()" yourself in some way.
Technically speaking that is incorrect; cegui does have this functionality built-in: CEGUI::System::getSingleton().getGUISheet()->getActiveChild().
Regarding copy/paste, it depends on how widly available you want to copied/cut data to be. If it's only going to be process-specific, I'm sure you won't have any trouble figuring it out. If you want the data to be system-wide, there are many examples on the web for accessing the system clipboard.
Regarding undo/redo, you might try looking into some design patterns like: Command Pattern or Memento Pattern.
That is odd. It must have been a bug in a previous version, as I'm using it to find the active/focused widget and works fine for me in v0.6.1.
The catch is that it will return child/auto widgets, so say if you where using a Combobox and are typing into the child Editbox it would return the Editbox - so you would have to traverse the parent hierarchy to get to the Combobox; that could be misperceived as not working if you had different expectations.
The catch is that it will return child/auto widgets, so say if you where using a Combobox and are typing into the child Editbox it would return the Editbox - so you would have to traverse the parent hierarchy to get to the Combobox; that could be misperceived as not working if you had different expectations.
Thanks Pompei2, I'll have a look at it. I want all these operations to work for a single instance of the editbox at the moment, so getting active widget is not a problem for me. When a person types some text in or selects and deletes text I'd like to be able to undo/redo these changes. How can I keep track of changes in the edit box in real time?
Thanks.
Thanks.
sjcomp wrote:When a person types some text in or selects and deletes text I'd like to be able to undo/redo these changes. How can I keep track of changes in the edit box in real time?
Jamarr wrote:Regarding undo/redo, you might try looking into some design patterns like: Command Pattern or Memento Pattern.
Who is online
Users browsing this forum: No registered users and 4 guests