Index: binaries/data/mods/mod/gui/gui.rnc
===================================================================
--- binaries/data/mods/mod/gui/gui.rnc
+++ binaries/data/mods/mod/gui/gui.rnc
@@ -68,6 +68,7 @@
attribute maxwidth { xsd:decimal }? &
attribute multiline { bool }?&
attribute offset { pos }?&
+ attribute readonly { bool }?&
attribute scrollbar { bool }?&
attribute scrollbar_style { text }?&
attribute scroll_bottom { bool }?&
Index: binaries/data/mods/mod/gui/gui.rng
===================================================================
--- binaries/data/mods/mod/gui/gui.rng
+++ binaries/data/mods/mod/gui/gui.rng
@@ -277,6 +277,11 @@
+
+
+
+
+
Index: binaries/data/mods/public/gui/replaymenu/replay_menu.js
===================================================================
--- binaries/data/mods/public/gui/replaymenu/replay_menu.js
+++ binaries/data/mods/public/gui/replaymenu/replay_menu.js
@@ -271,7 +271,7 @@
Engine.GetGUIObjectByName("sgVictory").caption = translateVictoryCondition(replay.attribs.settings.GameType);
Engine.GetGUIObjectByName("sgNbPlayers").caption = sprintf(translate("Players: %(numberOfPlayers)s"),
{ "numberOfPlayers": replay.attribs.settings.PlayerData.length });
- Engine.GetGUIObjectByName("replayFilename").caption = escapeText(Engine.GetReplayDirectoryName(replay.directory));
+ Engine.GetGUIObjectByName("replayFilename").caption = Engine.GetReplayDirectoryName(replay.directory);
let metadata = Engine.GetReplayMetadata(replay.directory);
Engine.GetGUIObjectByName("sgPlayersNames").caption =
Index: binaries/data/mods/public/gui/replaymenu/replay_menu.xml
===================================================================
--- binaries/data/mods/public/gui/replaymenu/replay_menu.xml
+++ binaries/data/mods/public/gui/replaymenu/replay_menu.xml
@@ -106,7 +106,7 @@
-
+
Index: source/gui/CInput.h
===================================================================
--- source/gui/CInput.h
+++ source/gui/CInput.h
@@ -65,6 +65,16 @@
virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev);
/**
+ * Handle events manually to catch keys which change the text.
+ */
+ virtual void ManuallyMutableHandleEvent(const int szChar);
+
+ /**
+ * Handle events manually to catch keys which don't change the text.
+ */
+ virtual void ManuallyImmutableHandleEvent(const int szChar);
+
+ /**
* Handle hotkey events (called by ManuallyHandleEvent)
*/
virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev);
@@ -174,6 +184,9 @@
/// If the cursor should be drawn or not.
bool m_CursorVisState;
+
+ /// If true it allows to user only select the text by mouse and copy by hotkey.
+ bool m_Readonly;
};
#endif // INCLUDED_CINPUT
Index: source/gui/CInput.cpp
===================================================================
--- source/gui/CInput.cpp
+++ source/gui/CInput.cpp
@@ -44,7 +44,7 @@
CInput::CInput()
: m_iBufferPos(-1), m_iBufferPos_Tail(-1), m_SelectingText(false), m_HorizontalScroll(0.f),
m_PrevTime(0.0), m_CursorVisState(true), m_CursorBlinkRate(0.5), m_ComposingText(false),
- m_iComposedLength(0), m_iComposedPos(0), m_iInsertPos(0)
+ m_iComposedLength(0), m_iComposedPos(0), m_iInsertPos(0), m_Readonly(false)
{
AddSetting(GUIST_int, "buffer_position");
AddSetting(GUIST_float, "buffer_zone");
@@ -55,6 +55,7 @@
AddSetting(GUIST_bool, "mask");
AddSetting(GUIST_int, "max_length");
AddSetting(GUIST_bool, "multiline");
+ AddSetting(GUIST_bool, "readonly");
AddSetting(GUIST_bool, "scrollbar");
AddSetting(GUIST_CStr, "scrollbar_style");
AddSetting(GUIST_CGUISpriteInstance, "sprite");
@@ -96,6 +97,10 @@
{
ENSURE(m_iBufferPos != -1);
+ // Readonly mode allows to use mouse and keyboard to select and copy the text only
+ if (m_Readonly && ev->ev.type != SDL_HOTKEYDOWN && ev->ev.type != SDL_KEYDOWN)
+ return IN_PASS;
+
if (ev->ev.type == SDL_HOTKEYDOWN)
{
if (m_ComposingText)
@@ -186,345 +191,369 @@
{
if (m_ComposingText)
return IN_HANDLED;
- // Since the GUI framework doesn't handle to set settings
- // in Unicode (CStrW), we'll simply retrieve the actual
- // pointer and edit that.
- CStrW* pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
- bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
int szChar = 0;
if (ev->ev.type == SDL_KEYDOWN)
szChar = ev->ev.key.keysym.sym;
- wchar_t cooked = 0;
- switch (szChar)
- {
- case SDLK_TAB: // '\t'
- /* Auto Complete */
- // We just send the tab event to JS and let it figure out autocomplete.
- SendEvent(GUIM_TAB, "tab");
- break;
+ ManuallyImmutableHandleEvent(szChar);
+ if (!m_Readonly)
+ ManuallyMutableHandleEvent(szChar);
- case SDLK_BACKSPACE: // '\b'
- m_WantedX = 0.0f;
+ UpdateBufferPositionSetting();
+ return IN_HANDLED;
+ }
- if (SelectingText())
- DeleteCurSelection();
- else
- {
- m_iBufferPos_Tail = -1;
+ return IN_PASS;
+}
- if (pCaption->empty() || m_iBufferPos == 0)
- break;
- if (m_iBufferPos == (int)pCaption->length())
- *pCaption = pCaption->Left((long)pCaption->length()-1);
- else
- *pCaption = pCaption->Left(m_iBufferPos-1) +
- pCaption->Right((long)pCaption->length()-m_iBufferPos);
+void CInput::ManuallyMutableHandleEvent(const int szChar)
+{
+ // Since the GUI framework doesn't handle to set settings
+ // in Unicode (CStrW), we'll simply retrieve the actual
+ // pointer and edit that.
+ CStrW* pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
+ wchar_t cooked = 0;
- --m_iBufferPos;
+ switch (szChar)
+ {
+ case SDLK_TAB: // '\t'
+ /* Auto Complete */
+ // We just send the tab event to JS and let it figure out autocomplete.
+ SendEvent(GUIM_TAB, "tab");
+ break;
- UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
+ case SDLK_BACKSPACE: // '\b'
+ m_WantedX = 0.0f;
- }
+ if (SelectingText())
+ DeleteCurSelection();
+ else
+ {
+ m_iBufferPos_Tail = -1;
- UpdateAutoScroll();
- break;
+ if (pCaption->empty() || m_iBufferPos == 0)
+ break;
- case SDLK_DELETE:
- m_WantedX = 0.0f;
- // If selection:
- if (SelectingText())
- DeleteCurSelection();
+ if (m_iBufferPos == (int)pCaption->length())
+ *pCaption = pCaption->Left((long)pCaption->length() - 1);
else
- {
- if (pCaption->empty() || m_iBufferPos == (int)pCaption->length())
- break;
+ *pCaption = pCaption->Left(m_iBufferPos - 1) +
+ pCaption->Right((long)pCaption->length() - m_iBufferPos);
- *pCaption = pCaption->Left(m_iBufferPos) +
- pCaption->Right((long)pCaption->length()-(m_iBufferPos+1));
+ --m_iBufferPos;
- UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
- }
+ UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos);
- UpdateAutoScroll();
- break;
+ }
- case SDLK_HOME:
- // If there's not a selection, we should create one now
- if (!shiftKeyPressed)
- {
- // Make sure a selection isn't created.
- m_iBufferPos_Tail = -1;
- }
- else if (!SelectingText())
- {
- // Place tail at the current point:
- m_iBufferPos_Tail = m_iBufferPos;
- }
+ UpdateAutoScroll();
+ break;
- m_iBufferPos = 0;
- m_WantedX = 0.0f;
+ case SDLK_DELETE:
+ m_WantedX = 0.0f;
+ // If selection:
+ if (SelectingText())
+ DeleteCurSelection();
+ else
+ {
+ if (pCaption->empty() || m_iBufferPos == (int)pCaption->length())
+ break;
- UpdateAutoScroll();
- break;
+ *pCaption = pCaption->Left(m_iBufferPos) +
+ pCaption->Right((long)pCaption->length() - (m_iBufferPos + 1));
- case SDLK_END:
- // If there's not a selection, we should create one now
- if (!shiftKeyPressed)
- {
- // Make sure a selection isn't created.
- m_iBufferPos_Tail = -1;
- }
- else if (!SelectingText())
- {
- // Place tail at the current point:
- m_iBufferPos_Tail = m_iBufferPos;
- }
+ UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos);
+ }
- m_iBufferPos = (long)pCaption->length();
- m_WantedX = 0.0f;
+ UpdateAutoScroll();
+ break;
- UpdateAutoScroll();
+ case SDLK_KP_ENTER:
+ case SDLK_RETURN:
+ // 'Return' should do a Press event for single liners (e.g. submitting forms)
+ // otherwise a '\n' character will be added.
+ {
+ bool multiline;
+ GUI::GetSetting(this, "multiline", multiline);
+ if (!multiline)
+ {
+ SendEvent(GUIM_PRESSED, "press");
break;
+ }
- /**
- * Conventions for Left/Right when text is selected:
- *
- * References:
- *
- * Visual Studio
- * Visual Studio has the 'newer' approach, used by newer versions of
- * things, and in newer applications. A left press will always place
- * the pointer on the left edge of the selection, and then of course
- * remove the selection. Right will do the exact same thing.
- * If you have the pointer on the right edge and press right, it will
- * in other words just remove the selection.
- *
- * Windows (eg. Notepad)
- * A left press always takes the pointer a step to the left and
- * removes the selection as if it were never there in the first place.
- * Right of course does the same thing but to the right.
- *
- * I chose the Visual Studio convention. Used also in Word, gtk 2.0, MSN
- * Messenger.
- */
- case SDLK_LEFT:
- m_WantedX = 0.f;
-
- if (shiftKeyPressed || !SelectingText())
- {
- if (!shiftKeyPressed)
- m_iBufferPos_Tail = -1;
- else if (!SelectingText())
- m_iBufferPos_Tail = m_iBufferPos;
+ cooked = '\n'; // Change to '\n' and do default:
+ // NOTE: Fall-through
+ }
+ default: // Insert a character
+ {
+ // In SDL2, we no longer get Unicode wchars via SDL_Keysym
+ // we use text input events instead and they provide UTF-8 chars
+ if (cooked == 0)
+ return;
+
+ // check max length
+ int max_length;
+ GUI::GetSetting(this, "max_length", max_length);
+ if (max_length != 0 && (int)pCaption->length() >= max_length)
+ break;
- if (m_iBufferPos > 0)
- --m_iBufferPos;
- }
- else
- {
- if (m_iBufferPos_Tail < m_iBufferPos)
- m_iBufferPos = m_iBufferPos_Tail;
+ m_WantedX = 0.0f;
- m_iBufferPos_Tail = -1;
- }
+ if (SelectingText())
+ DeleteCurSelection();
+ m_iBufferPos_Tail = -1;
- UpdateAutoScroll();
- break;
+ if (m_iBufferPos == (int)pCaption->length())
+ *pCaption += cooked;
+ else
+ *pCaption = pCaption->Left(m_iBufferPos) + cooked +
+ pCaption->Right((long)pCaption->length() - m_iBufferPos);
- case SDLK_RIGHT:
- m_WantedX = 0.0f;
+ UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos + 1);
- if (shiftKeyPressed || !SelectingText())
- {
- if (!shiftKeyPressed)
- m_iBufferPos_Tail = -1;
- else if (!SelectingText())
- m_iBufferPos_Tail = m_iBufferPos;
+ ++m_iBufferPos;
- if (m_iBufferPos < (int)pCaption->length())
- ++m_iBufferPos;
- }
- else
- {
- if (m_iBufferPos_Tail > m_iBufferPos)
- m_iBufferPos = m_iBufferPos_Tail;
+ UpdateAutoScroll();
+ break;
+ }
+ }
+}
- m_iBufferPos_Tail = -1;
- }
- UpdateAutoScroll();
- break;
+void CInput::ManuallyImmutableHandleEvent(const int szChar)
+{
+ // Since the GUI framework doesn't handle to set settings
+ // in Unicode (CStrW), we'll simply retrieve the actual
+ // pointer and edit that.
+ CStrW* pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
+ bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
- /**
- * Conventions for Up/Down when text is selected:
- *
- * References:
- *
- * Visual Studio
- * Visual Studio has a very strange approach, down takes you below the
- * selection to the next row, and up to the one prior to the whole
- * selection. The weird part is that it is always aligned as the
- * 'pointer'. I decided this is to much work for something that is
- * a bit arbitrary
- *
- * Windows (eg. Notepad)
- * Just like with left/right, the selection is destroyed and it moves
- * just as if there never were a selection.
- *
- * I chose the Notepad convention even though I use the VS convention with
- * left/right.
- */
- case SDLK_UP:
+ switch (szChar)
+ {
+ case SDLK_HOME:
+ // If there's not a selection, we should create one now
+ if (!shiftKeyPressed)
{
- if (!shiftKeyPressed)
- m_iBufferPos_Tail = -1;
- else if (!SelectingText())
- m_iBufferPos_Tail = m_iBufferPos;
+ // Make sure a selection isn't created.
+ m_iBufferPos_Tail = -1;
+ }
+ else if (!SelectingText())
+ {
+ // Place tail at the current point:
+ m_iBufferPos_Tail = m_iBufferPos;
+ }
- std::list::iterator current = m_CharacterPositions.begin();
- while (current != m_CharacterPositions.end())
- {
- if (m_iBufferPos >= current->m_ListStart &&
- m_iBufferPos <= current->m_ListStart+(int)current->m_ListOfX.size())
- break;
+ m_iBufferPos = 0;
+ m_WantedX = 0.0f;
- ++current;
- }
+ UpdateAutoScroll();
+ break;
- float pos_x;
+ case SDLK_END:
+ // If there's not a selection, we should create one now
+ if (!shiftKeyPressed)
+ {
+ // Make sure a selection isn't created.
+ m_iBufferPos_Tail = -1;
+ }
+ else if (!SelectingText())
+ {
+ // Place tail at the current point:
+ m_iBufferPos_Tail = m_iBufferPos;
+ }
- if (m_iBufferPos-current->m_ListStart == 0)
- pos_x = 0.f;
- else
- pos_x = current->m_ListOfX[m_iBufferPos-current->m_ListStart-1];
+ m_iBufferPos = (long)pCaption->length();
+ m_WantedX = 0.0f;
- if (m_WantedX > pos_x)
- pos_x = m_WantedX;
+ UpdateAutoScroll();
+ break;
- // Now change row:
- if (current != m_CharacterPositions.begin())
- {
- --current;
+ /**
+ * Conventions for Left/Right when text is selected:
+ *
+ * References:
+ *
+ * Visual Studio
+ * Visual Studio has the 'newer' approach, used by newer versions of
+ * things, and in newer applications. A left press will always place
+ * the pointer on the left edge of the selection, and then of course
+ * remove the selection. Right will do the exact same thing.
+ * If you have the pointer on the right edge and press right, it will
+ * in other words just remove the selection.
+ *
+ * Windows (eg. Notepad)
+ * A left press always takes the pointer a step to the left and
+ * removes the selection as if it were never there in the first place.
+ * Right of course does the same thing but to the right.
+ *
+ * I chose the Visual Studio convention. Used also in Word, gtk 2.0, MSN
+ * Messenger.
+ */
+ case SDLK_LEFT:
+ m_WantedX = 0.f;
- // Find X-position:
- m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX);
- }
- // else we can't move up
+ if (shiftKeyPressed || !SelectingText())
+ {
+ if (!shiftKeyPressed)
+ m_iBufferPos_Tail = -1;
+ else if (!SelectingText())
+ m_iBufferPos_Tail = m_iBufferPos;
- UpdateAutoScroll();
- break;
+ if (m_iBufferPos > 0)
+ --m_iBufferPos;
+ }
+ else
+ {
+ if (m_iBufferPos_Tail < m_iBufferPos)
+ m_iBufferPos = m_iBufferPos_Tail;
+
+ m_iBufferPos_Tail = -1;
}
- case SDLK_DOWN:
+ UpdateAutoScroll();
+ break;
+
+ case SDLK_RIGHT:
+ m_WantedX = 0.0f;
+
+ if (shiftKeyPressed || !SelectingText())
{
if (!shiftKeyPressed)
m_iBufferPos_Tail = -1;
else if (!SelectingText())
m_iBufferPos_Tail = m_iBufferPos;
- std::list::iterator current = m_CharacterPositions.begin();
- while (current != m_CharacterPositions.end())
- {
- if (m_iBufferPos >= current->m_ListStart &&
- m_iBufferPos <= current->m_ListStart+(int)current->m_ListOfX.size())
- break;
+ if (m_iBufferPos < (int)pCaption->length())
+ ++m_iBufferPos;
+ }
+ else
+ {
+ if (m_iBufferPos_Tail > m_iBufferPos)
+ m_iBufferPos = m_iBufferPos_Tail;
- ++current;
- }
+ m_iBufferPos_Tail = -1;
+ }
- float pos_x;
+ UpdateAutoScroll();
+ break;
- if (m_iBufferPos-current->m_ListStart == 0)
- pos_x = 0.f;
- else
- pos_x = current->m_ListOfX[m_iBufferPos-current->m_ListStart-1];
+ /**
+ * Conventions for Up/Down when text is selected:
+ *
+ * References:
+ *
+ * Visual Studio
+ * Visual Studio has a very strange approach, down takes you below the
+ * selection to the next row, and up to the one prior to the whole
+ * selection. The weird part is that it is always aligned as the
+ * 'pointer'. I decided this is to much work for something that is
+ * a bit arbitrary
+ *
+ * Windows (eg. Notepad)
+ * Just like with left/right, the selection is destroyed and it moves
+ * just as if there never were a selection.
+ *
+ * I chose the Notepad convention even though I use the VS convention with
+ * left/right.
+ */
+ case SDLK_UP:
+ {
+ if (!shiftKeyPressed)
+ m_iBufferPos_Tail = -1;
+ else if (!SelectingText())
+ m_iBufferPos_Tail = m_iBufferPos;
- if (m_WantedX > pos_x)
- pos_x = m_WantedX;
+ std::list::iterator current = m_CharacterPositions.begin();
+ while (current != m_CharacterPositions.end())
+ {
+ if (m_iBufferPos >= current->m_ListStart &&
+ m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size())
+ break;
- // Now change row:
- // Add first, so we can check if it's .end()
++current;
- if (current != m_CharacterPositions.end())
- {
- // Find X-position:
- m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX);
- }
- // else we can't move up
-
- UpdateAutoScroll();
- break;
}
- case SDLK_PAGEUP:
- GetScrollBar(0).ScrollMinusPlenty();
- UpdateAutoScroll();
- break;
+ float pos_x;
- case SDLK_PAGEDOWN:
- GetScrollBar(0).ScrollPlusPlenty();
- UpdateAutoScroll();
- break;
- /* END: Message History Lookup */
+ if (m_iBufferPos - current->m_ListStart == 0)
+ pos_x = 0.f;
+ else
+ pos_x = current->m_ListOfX[m_iBufferPos - current->m_ListStart - 1];
+
+ if (m_WantedX > pos_x)
+ pos_x = m_WantedX;
- case SDLK_KP_ENTER:
- case SDLK_RETURN:
- // 'Return' should do a Press event for single liners (e.g. submitting forms)
- // otherwise a '\n' character will be added.
+ // Now change row:
+ if (current != m_CharacterPositions.begin())
{
- bool multiline;
- GUI::GetSetting(this, "multiline", multiline);
- if (!multiline)
- {
- SendEvent(GUIM_PRESSED, "press");
- break;
- }
+ --current;
- cooked = '\n'; // Change to '\n' and do default:
- // NOTE: Fall-through
+ // Find X-position:
+ m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX);
}
- default: // Insert a character
- {
- // In SDL2, we no longer get Unicode wchars via SDL_Keysym
- // we use text input events instead and they provide UTF-8 chars
- if (ev->ev.type == SDL_KEYDOWN && cooked == 0)
- return IN_HANDLED;
-
- // check max length
- int max_length;
- GUI::GetSetting(this, "max_length", max_length);
- if (max_length != 0 && (int)pCaption->length() >= max_length)
- break;
+ // else we can't move up
- m_WantedX = 0.0f;
+ UpdateAutoScroll();
+ break;
+ }
- if (SelectingText())
- DeleteCurSelection();
+ case SDLK_DOWN:
+ {
+ if (!shiftKeyPressed)
m_iBufferPos_Tail = -1;
+ else if (!SelectingText())
+ m_iBufferPos_Tail = m_iBufferPos;
- if (m_iBufferPos == (int)pCaption->length())
- *pCaption += cooked;
- else
- *pCaption = pCaption->Left(m_iBufferPos) + cooked +
- pCaption->Right((long) pCaption->length()-m_iBufferPos);
+ std::list::iterator current = m_CharacterPositions.begin();
+ while (current != m_CharacterPositions.end())
+ {
+ if (m_iBufferPos >= current->m_ListStart &&
+ m_iBufferPos <= current->m_ListStart + (int)current->m_ListOfX.size())
+ break;
- UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
+ ++current;
+ }
- ++m_iBufferPos;
+ float pos_x;
- UpdateAutoScroll();
- break;
- }
+ if (m_iBufferPos - current->m_ListStart == 0)
+ pos_x = 0.f;
+ else
+ pos_x = current->m_ListOfX[m_iBufferPos - current->m_ListStart - 1];
+
+ if (m_WantedX > pos_x)
+ pos_x = m_WantedX;
+
+ // Now change row:
+ // Add first, so we can check if it's .end()
+ ++current;
+ if (current != m_CharacterPositions.end())
+ {
+ // Find X-position:
+ m_iBufferPos = current->m_ListStart + GetXTextPosition(current, pos_x, m_WantedX);
}
+ // else we can't move up
- UpdateBufferPositionSetting();
- return IN_HANDLED;
+ UpdateAutoScroll();
+ break;
}
- return IN_PASS;
+ case SDLK_PAGEUP:
+ GetScrollBar(0).ScrollMinusPlenty();
+ UpdateAutoScroll();
+ break;
+
+ case SDLK_PAGEDOWN:
+ GetScrollBar(0).ScrollPlusPlenty();
+ UpdateAutoScroll();
+ break;
+ /* END: Message History Lookup */
+
+ default:
+ break;
+ }
}
@@ -534,6 +563,9 @@
bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
std::string hotkey = static_cast(ev->ev.user.data1);
+ if (m_Readonly && hotkey != "copy" && hotkey != "text.move.left" && hotkey != "text.move.right")
+ return IN_PASS;
+
if (hotkey == "paste")
{
m_WantedX = 0.0f;
@@ -847,6 +879,9 @@
UpdateText();
}
UpdateAutoScroll();
+
+ if (Message.value == CStr("readonly"))
+ GUI::GetSetting(this, "readonly", m_Readonly);
break;
}
@@ -1031,6 +1066,8 @@
UpdateText();
UpdateAutoScroll();
+
+ GUI::GetSetting(this, "readonly", m_Readonly);
break;
}