#include "widgets/lineedit/lineedit.h" #include "core/utf8reader.h" #include "core/colorf.h" LineEdit::LineEdit(Widget* parent) : Widget(parent) { SetNoncontentSizes(5.0, 3.0, 5.0, 3.0); timer = new Timer(this); timer->FuncExpired = [=]() { OnTimerExpired(); }; scroll_timer = new Timer(this); scroll_timer->FuncExpired = [=]() { OnScrollTimerExpired(); }; SetCursor(StandardCursor::ibeam); } LineEdit::~LineEdit() { } bool LineEdit::IsReadOnly() const { return readonly; } LineEdit::Alignment LineEdit::GetAlignment() const { return align_left; } bool LineEdit::IsLowercase() const { return lowercase; } bool LineEdit::IsUppercase() const { return uppercase; } bool LineEdit::IsPasswordMode() const { return password_mode; } int LineEdit::GetMaxLength() const { return max_length; } std::string LineEdit::GetText() const { return text; } int LineEdit::GetTextInt() const { return std::atoi(text.c_str()); } float LineEdit::GetTextFloat() const { return (float)std::atof(text.c_str()); } std::string LineEdit::GetSelection() const { int start = std::min(selection_start, selection_start + selection_length); return text.substr(start, std::abs(selection_length)); } int LineEdit::GetSelectionStart() const { return selection_start; } int LineEdit::GetSelectionLength() const { return selection_length; } int LineEdit::GetCursorPos() const { return cursor_pos; } Size LineEdit::GetTextSize() { Canvas* canvas = GetCanvas(); return GetVisualTextSize(canvas); } Size LineEdit::GetTextSize(const std::string& str) { Canvas* canvas = GetCanvas(); return canvas->measureText(str).size(); } double LineEdit::GetPreferredContentWidth() { return GetTextSize().width; } double LineEdit::GetPreferredContentHeight(double width) { return GetTextSize().height; } void LineEdit::SelectAll() { SetTextSelection(0, (int)text.size()); Update(); } void LineEdit::SetReadOnly(bool enable) { if (readonly != enable) { readonly = enable; Update(); } } void LineEdit::SetAlignment(Alignment newalignment) { if (alignment != newalignment) { alignment = newalignment; Update(); } } void LineEdit::SetLowercase(bool enable) { if (lowercase != enable) { lowercase = enable; text = ToLower(text); Update(); } } void LineEdit::SetUppercase(bool enable) { if (uppercase != enable) { uppercase = enable; text = ToUpper(text); Update(); } } void LineEdit::SetPasswordMode(bool enable) { if (password_mode != enable) { password_mode = enable; Update(); } } void LineEdit::SetMaxLength(int length) { if (max_length != length) { max_length = length; if ((int)text.length() > length) { if (FuncBeforeEditChanged) FuncBeforeEditChanged(); text = text.substr(0, length); if (FuncAfterEditChanged) FuncAfterEditChanged(); } Update(); } } void LineEdit::SetText(const std::string& newtext) { if (lowercase) text = ToLower(newtext); else if (uppercase) text = ToUpper(newtext); else text = newtext; clip_start_offset = 0; UpdateTextClipping(); SetCursorPos((int)text.size()); SetTextSelection(0, 0); Update(); } void LineEdit::SetTextInt(int number) { text = std::to_string(number); clip_start_offset = 0; UpdateTextClipping(); SetCursorPos((int)text.size()); SetTextSelection(0, 0); Update(); } void LineEdit::SetTextFloat(float number, int num_decimal_places) { text = ToFixed(number, num_decimal_places); clip_start_offset = 0; UpdateTextClipping(); SetCursorPos((int)text.size()); SetTextSelection(0, 0); Update(); } void LineEdit::SetSelection(int pos, int length) { //don't call FuncSelectionChanged() here, because this //member is for public usage selection_start = pos; selection_length = length; Update(); } void LineEdit::ClearSelection() { //don't call FuncSelectionChanged() here, because this //member is for public usage SetSelection(0, 0); Update(); } void LineEdit::DeleteSelectedText() { if (GetSelectionLength() == 0) return; int sel_start = selection_start; int sel_end = selection_start + selection_length; if (sel_start > sel_end) std::swap(sel_start, sel_end); text = text.substr(0, sel_start) + text.substr(sel_end, text.size()); cursor_pos = sel_start; SetTextSelection(0, 0); int old_pos = GetCursorPos(); SetCursorPos(0); SetCursorPos(old_pos); } void LineEdit::SetCursorPos(int pos) { cursor_pos = pos; UpdateTextClipping(); Update(); } void LineEdit::SetInputMask(const std::string& mask) { input_mask = mask; } void LineEdit::SetNumericMode(bool enable, bool decimals) { numeric_mode = enable; numeric_mode_decimals = decimals; } void LineEdit::SetDecimalCharacter(const std::string& new_decimal_char) { decimal_char = new_decimal_char; } void LineEdit::SetSelectAllOnFocusGain(bool enable) { select_all_on_focus_gain = enable; } void LineEdit::OnMouseMove(const Point& pos) { if (mouse_selecting && !ignore_mouse_events) { if (pos.x < 0.0 || pos.x >= GetWidth()) { if (pos.x < 0.0) mouse_moves_left = true; else mouse_moves_left = false; if (!readonly) scroll_timer->Start(50, true); } else { scroll_timer->Stop(); cursor_pos = GetCharacterIndex(pos.x); SetSelectionLength(cursor_pos - selection_start); Update(); } } } bool LineEdit::OnMouseDown(const Point& pos, int key) { if (key == IK_LeftMouse) { if (HasFocus()) { CaptureMouse(); mouse_selecting = true; cursor_pos = GetCharacterIndex(pos.x); SetTextSelection(cursor_pos, 0); } else { SetFocus(); } Update(); } return true; } bool LineEdit::OnMouseDoubleclick(const Point& pos, int key) { return true; } bool LineEdit::OnMouseUp(const Point& pos, int key) { if (mouse_selecting && key == IK_LeftMouse) { if (ignore_mouse_events) // This prevents text selection from changing from what was set when focus was gained. { ReleaseMouseCapture(); ignore_mouse_events = false; mouse_selecting = false; } else { scroll_timer->Stop(); ReleaseMouseCapture(); mouse_selecting = false; int sel_end = GetCharacterIndex(pos.x); SetSelectionLength(sel_end - selection_start); cursor_pos = sel_end; SetFocus(); Update(); } } return true; } void LineEdit::OnKeyChar(std::string chars) { if (FuncFilterKeyChar) { chars = FuncFilterKeyChar(chars); if (chars.empty()) return; } if (!chars.empty() && !(chars[0] >= 0 && chars[0] < 32)) { if (FuncBeforeEditChanged) FuncBeforeEditChanged(); DeleteSelectedText(); if (input_mask.empty()) { if (numeric_mode) { // '-' can only be added once, and only as the first character. if (chars == "-" && cursor_pos == 0 && text.find("-") == std::string::npos) { if (InsertText(cursor_pos, chars)) cursor_pos += (int)chars.size(); } else if (numeric_mode_decimals && chars == decimal_char && cursor_pos > 0) // add decimal char { if (text.find(decimal_char) == std::string::npos) // allow only one decimal char. { if (InsertText(cursor_pos, chars)) cursor_pos += (int)chars.size(); } } else if (numeric_mode_characters.find(chars) != std::string::npos) // 0-9 { if (InsertText(cursor_pos, chars)) cursor_pos += (int)chars.size(); } } else { // not in any special mode, just insert the string. if (InsertText(cursor_pos, chars)) cursor_pos += (int)chars.size(); } } else { if (InputMaskAcceptsInput(cursor_pos, chars)) { if (InsertText(cursor_pos, chars)) cursor_pos += (int)chars.size(); } } UpdateTextClipping(); if (FuncAfterEditChanged) FuncAfterEditChanged(); } } void LineEdit::OnKeyDown(EInputKey key) { if (FuncIgnoreKeyDown && FuncIgnoreKeyDown(key)) return; if (key == IK_Enter) { if (FuncEnterPressed) FuncEnterPressed(); return; } if (!readonly) // Do not flash cursor when readonly { cursor_blink_visible = true; timer->Start(500); // don't blink cursor when moving or typing. } if (key == IK_Enter || key == IK_Escape || key == IK_Tab) { // Do not consume these. return; } else if (key == IK_A && GetKeyState(IK_Ctrl)) { // select all SetTextSelection(0, (int)text.size()); cursor_pos = selection_length; UpdateTextClipping(); Update(); } else if (key == IK_C && GetKeyState(IK_Ctrl)) { if (!password_mode) // Do not allow copying the password to clipboard { std::string str = GetSelection(); SetClipboardText(str); } } else if (readonly) { // Do not consume messages on read only component (only allow CTRL-A and CTRL-C) return; } else if (key == IK_Left) { Move(-1, GetKeyState(IK_Ctrl), GetKeyState(IK_Shift)); } else if (key == IK_Right) { Move(1, GetKeyState(IK_Ctrl), GetKeyState(IK_Shift)); } else if (key == IK_Backspace) { Backspace(); UpdateTextClipping(); } else if (key == IK_Delete) { Del(); UpdateTextClipping(); } else if (key == IK_Home) { SetSelectionStart(cursor_pos); cursor_pos = 0; if (GetKeyState(IK_Shift)) SetSelectionLength(-selection_start); else SetTextSelection(0, 0); UpdateTextClipping(); Update(); } else if (key == IK_End) { SetSelectionStart(cursor_pos); cursor_pos = (int)text.size(); if (GetKeyState(IK_Shift)) SetSelectionLength((int)text.size() - selection_start); else SetTextSelection(0, 0); UpdateTextClipping(); Update(); } else if (key == IK_X && GetKeyState(IK_Ctrl)) { std::string str = GetSelection(); DeleteSelectedText(); SetClipboardText(str); UpdateTextClipping(); } else if (key == IK_V && GetKeyState(IK_Ctrl)) { std::string str = GetClipboardText(); std::string::const_iterator end_str = std::remove(str.begin(), str.end(), '\n'); str.resize(end_str - str.begin()); end_str = std::remove(str.begin(), str.end(), '\r'); str.resize(end_str - str.begin()); DeleteSelectedText(); if (input_mask.empty()) { if (numeric_mode) { std::string present_text = GetText(); bool present_minus = present_text.find('-') != std::string::npos; bool str_minus = str.find('-') != std::string::npos; if (!present_minus || !str_minus) { if ((!present_minus && !str_minus) || //if no minus found (str_minus && cursor_pos == 0 && str[0] == '-') || //if there's minus in text to paste (present_minus && cursor_pos > 0)) //if there's minus in the beginning of control's text { if (numeric_mode_decimals) { std::string::size_type decimal_point_pos; if ((decimal_point_pos = str.find_first_not_of(numeric_mode_characters, str[0] == '-' ? 1 : 0)) == std::string::npos) //no decimal char inside string to paste { //we don't look at the position of decimal char inside of text in the textbox, if it's present if (InsertText(cursor_pos, str)) SetCursorPos(cursor_pos + (int)str.length()); } else { if (present_text.find(decimal_char) == std::string::npos && str[decimal_point_pos] == decimal_char[0] && str.find_first_not_of(numeric_mode_characters, decimal_point_pos + 1) == std::string::npos) //allow only one decimal char in the string to paste { if (InsertText(cursor_pos, str)) SetCursorPos(cursor_pos + (int)str.length()); } } } else { if (str.find_first_not_of(numeric_mode_characters, str[0] == '-' ? 1 : 0) == std::string::npos) { if (InsertText(cursor_pos, str)) SetCursorPos(cursor_pos + (int)str.length()); } } } } } else { if (InsertText(cursor_pos, str)) SetCursorPos(cursor_pos + (int)str.length()); } } else { if (InputMaskAcceptsInput(cursor_pos, str)) { if (InsertText(cursor_pos, str)) SetCursorPos(cursor_pos + (int)str.length()); } } UpdateTextClipping(); } else if (GetKeyState(IK_Ctrl) && key == IK_Z) { if (!readonly) { std::string tmp = undo_info.undo_text; undo_info.undo_text = GetText(); SetText(tmp); } } else if (key == IK_Shift) { if (selection_start == -1) SetTextSelection(cursor_pos, 0); } if (FuncAfterEditChanged) FuncAfterEditChanged(); } void LineEdit::OnKeyUp(EInputKey key) { } void LineEdit::OnSetFocus() { if (!readonly) timer->Start(500); if (select_all_on_focus_gain) SelectAll(); ignore_mouse_events = true; cursor_pos = (int)text.length(); Update(); if (FuncFocusGained) FuncFocusGained(); } void LineEdit::OnLostFocus() { timer->Stop(); SetTextSelection(0, 0); Update(); if (FuncFocusLost) FuncFocusLost(); } void LineEdit::Move(int steps, bool ctrl, bool shift) { if (shift && selection_length == 0) SetSelectionStart(cursor_pos); // Jump over words if control is pressed. if (ctrl) { if (steps < 0) steps = FindPreviousBreakCharacter(cursor_pos - 1) - cursor_pos; else steps = FindNextBreakCharacter(cursor_pos + 1) - cursor_pos; cursor_pos += steps; if (cursor_pos < 0) cursor_pos = 0; if (cursor_pos > (int)text.size()) cursor_pos = (int)text.size(); } else { UTF8Reader utf8_reader(text.data(), text.length()); utf8_reader.set_position(cursor_pos); if (steps > 0) { for (int i = 0; i < steps; i++) utf8_reader.next(); } else if (steps < 0) { for (int i = 0; i < -steps; i++) utf8_reader.prev(); } cursor_pos = (int)utf8_reader.position(); } // Clear the selection if a cursor key is pressed but shift isn't down. if (shift) SetSelectionLength(cursor_pos - selection_start); else SetTextSelection(-1, 0); UpdateTextClipping(); Update(); undo_info.first_text_insert = true; } bool LineEdit::InsertText(int pos, const std::string& str) { undo_info.first_erase = false; if (undo_info.first_text_insert) { undo_info.undo_text = GetText(); undo_info.first_text_insert = false; } // checking if insert exceeds max length if (UTF8Reader::utf8_length(text) + UTF8Reader::utf8_length(str) > max_length) { return false; } if (lowercase) text.insert(pos, ToLower(str)); else if (uppercase) text.insert(pos, ToUpper(str)); else text.insert(pos, str); UpdateTextClipping(); Update(); return true; } void LineEdit::Backspace() { if (undo_info.first_erase) { undo_info.first_erase = false; undo_info.undo_text = GetText(); } if (GetSelectionLength() != 0) { DeleteSelectedText(); Update(); } else { if (cursor_pos > 0) { UTF8Reader utf8_reader(text.data(), text.length()); utf8_reader.set_position(cursor_pos); utf8_reader.prev(); size_t length = utf8_reader.char_length(); text.erase(cursor_pos - length, length); cursor_pos -= (int)length; Update(); } } int old_pos = GetCursorPos(); SetCursorPos(0); SetCursorPos(old_pos); } void LineEdit::Del() { if (undo_info.first_erase) { undo_info.first_erase = false; undo_info.undo_text = GetText(); } if (GetSelectionLength() != 0) { DeleteSelectedText(); Update(); } else { if (cursor_pos < (int)text.size()) { UTF8Reader utf8_reader(text.data(), text.length()); utf8_reader.set_position(cursor_pos); size_t length = utf8_reader.char_length(); text.erase(cursor_pos, length); Update(); } } } int LineEdit::GetCharacterIndex(double mouse_x) { if (text.size() <= 1) { return (int)text.size(); } Canvas* canvas = GetCanvas(); UTF8Reader utf8_reader(text.data(), text.length()); int seek_start = clip_start_offset; int seek_end = (int)text.size(); int seek_center = (seek_start + seek_end) / 2; //fast search while (true) { utf8_reader.set_position(seek_center); utf8_reader.move_to_leadbyte(); seek_center = (int)utf8_reader.position(); Size text_size = GetVisualTextSize(canvas, clip_start_offset, seek_center - clip_start_offset); if (text_size.width > mouse_x) seek_end = seek_center; else seek_start = seek_center; if (seek_end - seek_start < 7) break; //go to accurate search seek_center = (seek_start + seek_end) / 2; } utf8_reader.set_position(seek_start); utf8_reader.move_to_leadbyte(); //accurate search while (true) { seek_center = (int)utf8_reader.position(); Size text_size = GetVisualTextSize(canvas, clip_start_offset, seek_center - clip_start_offset); if (text_size.width > mouse_x || utf8_reader.is_end()) break; utf8_reader.next(); } return seek_center; } void LineEdit::UpdateTextClipping() { Canvas* canvas = GetCanvas(); if (!canvas) return; Size text_size = GetVisualTextSize(canvas, clip_start_offset, (int)text.size() - clip_start_offset); if (cursor_pos < clip_start_offset) clip_start_offset = cursor_pos; Rect cursor_rect = GetCursorRect(); UTF8Reader utf8_reader(text.data(), text.length()); double width = GetWidth(); while (cursor_rect.x + cursor_rect.width > width) { utf8_reader.set_position(clip_start_offset); utf8_reader.next(); clip_start_offset = (int)utf8_reader.position(); if (clip_start_offset == text.size()) break; cursor_rect = GetCursorRect(); } // Get number of chars of current text fitting in the lineedit. int search_upper = (int)text.size(); int search_lower = clip_start_offset; while (true) { int midpoint = (search_lower + search_upper) / 2; utf8_reader.set_position(midpoint); utf8_reader.move_to_leadbyte(); if (midpoint != utf8_reader.position()) utf8_reader.next(); midpoint = (int)utf8_reader.position(); if (midpoint == search_lower || midpoint == search_upper) break; Size midpoint_size = GetVisualTextSize(canvas, clip_start_offset, midpoint - clip_start_offset); if (width < midpoint_size.width) search_upper = midpoint; else search_lower = midpoint; } clip_end_offset = search_upper; if (cursor_rect.x < 0.0) { clip_start_offset = cursor_pos; } } Rect LineEdit::GetCursorRect() { Canvas* canvas = GetCanvas(); int substr_end = cursor_pos - clip_start_offset; if (substr_end < 0) substr_end = 0; std::string clipped_text = text.substr(clip_start_offset, substr_end); if (password_mode) { // If we are in password mode, we gonna return the right characters clipped_text = CreatePassword(UTF8Reader::utf8_length(clipped_text)); } Size text_size_before_cursor = canvas->measureText(clipped_text).size(); Rect cursor_rect; cursor_rect.x = text_size_before_cursor.width; cursor_rect.width = 1.0f; cursor_rect.y = vertical_text_align.top; cursor_rect.height = vertical_text_align.bottom - vertical_text_align.top; return cursor_rect; } Rect LineEdit::GetSelectionRect() { Canvas* canvas = GetCanvas(); // text before selection: std::string txt_before = GetVisibleTextBeforeSelection(); Size text_size_before_selection = canvas->measureText(txt_before).size(); // selection text: std::string txt_selected = GetVisibleSelectedText(); Size text_size_selection = canvas->measureText(txt_selected).size(); Rect selection_rect; selection_rect.x = text_size_before_selection.width; selection_rect.width = text_size_selection.width; selection_rect.y = vertical_text_align.top; selection_rect.height = vertical_text_align.bottom - vertical_text_align.top; return selection_rect; } int LineEdit::FindNextBreakCharacter(int search_start) { if (search_start >= int(text.size()) - 1) return (int)text.size(); size_t pos = text.find_first_of(break_characters, search_start); if (pos == std::string::npos) return (int)text.size(); return (int)pos; } int LineEdit::FindPreviousBreakCharacter(int search_start) { if (search_start <= 0) return 0; size_t pos = text.find_last_of(break_characters, search_start); if (pos == std::string::npos) return 0; return (int)pos; } void LineEdit::OnTimerExpired() { if (!IsVisible()) { timer->Stop(); return; } if (cursor_blink_visible) timer->Start(500); else timer->Start(500); cursor_blink_visible = !cursor_blink_visible; Update(); } void LineEdit::OnGeometryChanged() { Canvas* canvas = GetCanvas(); vertical_text_align = canvas->verticalTextAlign(); clip_start_offset = 0; cursor_pos = 0; UpdateTextClipping(); } std::string LineEdit::GetVisibleTextBeforeSelection() { std::string ret; int sel_start = std::min(selection_start, selection_start + selection_length); int start = std::min(sel_start, clip_start_offset); if (start < clip_start_offset) return ret; int end = std::min(sel_start, clip_end_offset); ret = text.substr(start, end - start); // If we are in password mode, we gonna return the right characters if (password_mode) ret = CreatePassword(UTF8Reader::utf8_length(ret)); return ret; } std::string LineEdit::GetVisibleSelectedText() { std::string ret; if (selection_length == 0) return ret; int sel_start = std::min(selection_start, selection_start + selection_length); int sel_end = std::max(selection_start, selection_start + selection_length); int end = std::min(clip_end_offset, sel_end); int start = std::max(clip_start_offset, sel_start); if (start > end) return ret; if (start == end) return ret; ret = text.substr(start, end - start); // If we are in password mode, we gonna return the right characters if (password_mode) ret = CreatePassword(UTF8Reader::utf8_length(ret)); return ret; } void LineEdit::SetSelectionStart(int start) { if (FuncSelectionChanged && selection_length && selection_start != start) FuncSelectionChanged(); selection_start = start; } void LineEdit::SetSelectionLength(int length) { if (FuncSelectionChanged && selection_length != length) FuncSelectionChanged(); selection_length = length; } void LineEdit::SetTextSelection(int start, int length) { if (FuncSelectionChanged && (selection_length != length || (selection_length && selection_start != start))) FuncSelectionChanged(); selection_start = start; selection_length = length; } std::string LineEdit::GetVisibleTextAfterSelection() { // returns the whole visible string if there is no selection. std::string ret; int sel_end = std::max(selection_start, selection_start + selection_length); int start = std::max(clip_start_offset, sel_end); int end = clip_end_offset; if (start > end) return ret; if (clip_end_offset == sel_end) return ret; if (sel_end <= 0) return ret; else { ret = text.substr(start, end - start); // If we are in password mode, we gonna return the right characters if (password_mode) ret = CreatePassword(UTF8Reader::utf8_length(ret)); return ret; } } void LineEdit::OnPaintFrame(Canvas* canvas) { double w = GetFrameGeometry().width; double h = GetFrameGeometry().height; Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); } void LineEdit::OnPaint(Canvas* canvas) { std::string txt_before = GetVisibleTextBeforeSelection(); std::string txt_selected = GetVisibleSelectedText(); std::string txt_after = GetVisibleTextAfterSelection(); if (txt_before.empty() && txt_selected.empty() && txt_after.empty()) { txt_after = text.substr(clip_start_offset, clip_end_offset - clip_start_offset); // If we are in password mode, we gonna return the right characters if (password_mode) txt_after = CreatePassword(UTF8Reader::utf8_length(txt_after)); } Size size_before = canvas->measureText(txt_before).size(); Size size_selected = canvas->measureText(txt_selected).size(); if (!txt_selected.empty()) { // Draw selection box. Rect selection_rect = GetSelectionRect(); canvas->fillRect(selection_rect, HasFocus() ? Colorf::fromRgba8(100, 100, 100) : Colorf::fromRgba8(68, 68, 68)); } // Draw text before selection if (!txt_before.empty()) { canvas->drawText(Point(0.0, canvas->verticalTextAlign().baseline), Colorf::fromRgba8(255, 255, 255), txt_before); } if (!txt_selected.empty()) { canvas->drawText(Point(size_before.width, canvas->verticalTextAlign().baseline), Colorf::fromRgba8(255, 255, 255), txt_selected); } if (!txt_after.empty()) { canvas->drawText(Point(size_before.width + size_selected.width, canvas->verticalTextAlign().baseline), Colorf::fromRgba8(255, 255, 255), txt_after); } // draw cursor if (HasFocus()) { if (cursor_blink_visible) { Rect cursor_rect = GetCursorRect(); canvas->fillRect(cursor_rect, Colorf::fromRgba8(255, 255, 255)); } } } void LineEdit::OnScrollTimerExpired() { if (mouse_moves_left) Move(-1, false, false); else Move(1, false, false); } void LineEdit::OnEnableChanged() { bool enabled = IsEnabled(); if (!enabled) { cursor_blink_visible = false; timer->Stop(); } Update(); } bool LineEdit::InputMaskAcceptsInput(int cursor_pos, const std::string& str) { return str.find_first_not_of(input_mask) == std::string::npos; } std::string LineEdit::CreatePassword(std::string::size_type num_letters) const { return std::string(num_letters, '*'); } Size LineEdit::GetVisualTextSize(Canvas* canvas, int pos, int npos) const { return canvas->measureText(password_mode ? CreatePassword(UTF8Reader::utf8_length(text.substr(pos, npos))) : text.substr(pos, npos)).size(); } Size LineEdit::GetVisualTextSize(Canvas* canvas) const { return canvas->measureText(password_mode ? CreatePassword(UTF8Reader::utf8_length(text)) : text).size(); } std::string LineEdit::ToFixed(float number, int num_decimal_places) { for (int i = 0; i < num_decimal_places; i++) number *= 10.0f; std::string val = std::to_string((int)std::round(number)); if ((int)val.size() < num_decimal_places) val.resize(num_decimal_places + 1, 0); return val.substr(0, val.size() - num_decimal_places) + "." + val.substr(val.size() - num_decimal_places); } std::string LineEdit::ToLower(const std::string& text) { return text; } std::string LineEdit::ToUpper(const std::string& text) { return text; } const std::string LineEdit::break_characters = " ::;,.-"; const std::string LineEdit::numeric_mode_characters = "0123456789";