Add an on-screen keyboard in the popup inputbox

This commit is contained in:
Henrik Rydgård
2026-02-26 16:06:35 +01:00
parent 930a95f8f7
commit c3a78724c7
8 changed files with 326 additions and 33 deletions
+96 -2
View File
@@ -800,18 +800,112 @@ std::string PopupTextInputChoice::ValueText() const {
return *value_;
}
LinearLayout *CreateSoftKeyboard(TextEdit *edit, bool *upperCase) {
LinearLayout *keyboard = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT));
// TODO: Make something a bit more international... Although we don't need that for domain names.
static struct {
std::string_view v; const char *tag;
} kbRows[] = {
{"1234567890-=", "A"},
{"qwertyuiop'[]", "L"},
{"asdfghjkl()", "L"},
{"zxcvbnm,.", "L"},
{"QWERTYUIOP'[]", "U"},
{"ASDFGHJKL()", "U"},
{"ZXCVBNM,.", "U"},
{"", "A"},
};
static const float space[] = {
0.0f, 10.0f, 20.0f, 30.0f, 10.0f, 20.0f, 30.0f, 30.0f,
};
static_assert(ARRAY_SIZE(kbRows) == ARRAY_SIZE(space));
keyboard->SetSpacing(5.0f);
for (int i = 0; i < ARRAY_SIZE(kbRows); i++) {
LinearLayout *row = keyboard->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)));
row->SetSpacing(5.0f);
row->Add(new Spacer(space[i]));
row->SetTag(kbRows[i].tag);
for (int j = 0; j < kbRows[i].v.length(); j++) {
char c = kbRows[i].v[j];
row->Add(new Button(StringFromFormat("%c", c), new LinearLayoutParams(40.0f, 50.0f)))->OnClick.Add([edit, c](EventParams &) {
edit->InsertAtCaret(StringFromFormat("%c", c).c_str());
});
}
bool visible = false;
switch (kbRows[i].tag[0]) {
case 'L': visible = !(*upperCase); break;
case 'U': visible = *upperCase; break;
case 'A': visible = true; break;
default: visible = false; break;
}
row->SetVisibility(visible ? V_VISIBLE : V_GONE);
switch (i) {
case 0:
// Add backspace button at the end of the first row.
row->Add(new Button("", ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(60.0f, 50.0f)))->OnClick.Add([edit](EventParams &) {
edit->Backspace();
});
break;
case 7:
// Special keys.
row->Add(new Button("Aa", new LinearLayoutParams(80.0f, 50.0f)))->OnClick.Add([edit, keyboard, upperCase](EventParams &) {
*upperCase = !(*upperCase);
// Work through visibility.
for (int i = 0; i < keyboard->GetNumSubviews(); i++) {
LinearLayout *row = (LinearLayout *)keyboard->GetViewByIndex(i);
switch (row->Tag()[0]) {
case 'L': row->SetVisibility(*upperCase ? V_GONE : V_VISIBLE); break;
case 'U': row->SetVisibility(*upperCase ? V_VISIBLE : V_GONE); break;
case 'A': row->SetVisibility(V_VISIBLE); break;
default: row->SetVisibility(V_GONE); break;
}
}
});
row->Add(new Button("Space", new LinearLayoutParams(200.0f, 50.0f)))->OnClick.Add([edit](EventParams &) {
edit->SetText(edit->GetText() + " ");
});
row->Add(new Button("", ImageID("I_ARROW_LEFT"), new LinearLayoutParams(60.0f, 50.0f)))->OnClick.Add([edit](EventParams &) {
edit->MoveLeft();
});
row->Add(new Button("", ImageID("I_ARROW_RIGHT"), new LinearLayoutParams(60.0f, 50.0f)))->OnClick.Add([edit](EventParams &) {
edit->MoveRight();
});
break;
}
}
return keyboard;
}
void TextEditPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
UIContext &dc = *screenManager()->getUIContext();
textEditValue_ = *value_;
LinearLayout *lin = parent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams((UI::Size)300, WRAP_CONTENT)));
edit_ = new TextEdit(textEditValue_, Title(), placeholder_, new LinearLayoutParams(1.0f));
LinearLayout *lin = parent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
edit_ = new TextEdit(textEditValue_, Title(), placeholder_, new LinearLayoutParams(1.0f, Gravity::G_VCENTER, Margins(8)));
edit_->SetMaxLen(maxLen_);
edit_->SetTextColor(dc.GetTheme().popupStyle.fgColor);
edit_->SetPasswordMasking(passwordMasking_);
lin->Add(edit_);
parent->Add(new Spacer(8.0f));
keyboard_ = parent->Add(CreateSoftKeyboard(edit_, &upperCase_));
if (System_GetPropertyBool(SYSPROP_HAS_KEYBOARD)) {
keyboard_->SetVisibility(V_GONE);
lin->Add(new Spacer(5.0f));
showKeyboardChoice_ = lin->Add(new Choice(ImageID("I_KEYBOARD"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)));
showKeyboardChoice_->OnClick.Add([this](EventParams &) {
keyboard_->SetVisibility(V_VISIBLE);
showKeyboardChoice_->SetEnabled(false);
});
}
UI::SetFocusedView(edit_);
}
+7
View File
@@ -220,6 +220,8 @@ private:
bool liveUpdate_;
};
LinearLayout *CreateSoftKeyboard(TextEdit *edit, bool *upperCase);
class TextEditPopupScreen : public PopupScreen {
public:
TextEditPopupScreen(std::string *value, std::string_view placeholder, std::string_view title, int maxLen)
@@ -235,12 +237,17 @@ public:
Event OnChange;
private:
virtual UI::Size PopupWidth() const override { return 600; }
void OnCompleted(DialogResult result) override;
TextEdit *edit_ = nullptr;
LinearLayout *keyboard_ = nullptr;
Choice *showKeyboardChoice_ = nullptr;
std::string *value_;
std::string textEditValue_;
std::string placeholder_;
int maxLen_;
bool upperCase_ = false;
bool passwordMasking_ = false;
};
+56 -20
View File
@@ -1206,19 +1206,34 @@ void TextEdit::Draw(UIContext &dc) {
dc.DrawTextRect(textToDisplay, textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_);
}
if (HasFocus()) {
// Hack to find the caret position. Might want to find a better way...
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, textToDisplay.substr(0, caret_), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_);
float caretX = w - scrollPos_;
if (caretX > bounds_.w) {
scrollPos_ += caretX - bounds_.w;
}
if (caretX < 0) {
scrollPos_ += caretX;
}
caretX += textX;
dc.FillRect(UI::Drawable(textColor), Bounds(caretX - 1, bounds_.y + 2, 3, bounds_.h - 4));
// Hack to find the caret position. Might want to find a better way...
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, textToDisplay.substr(0, caret_), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_);
float caretX = w - scrollPos_;
if (caretX > bounds_.w) {
scrollPos_ += caretX - bounds_.w;
}
if (caretX < 0) {
scrollPos_ += caretX;
}
caretX += textX;
dc.FillRect(UI::Drawable(textColor), Bounds(caretX - 1, bounds_.y + 2, 3, bounds_.h - 4));
if (selectAtX_ >= 0) {
caret_ = -1;
for (int i = 0; i <= text_.size(); i++) {
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, textToDisplay.substr(0, i), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_);
float charX = w - scrollPos_;
if (charX >= selectAtX_ - 3) {
caret_ = i;
break;
}
}
if (caret_ == -1) {
caret_ = (int)text_.size();
}
selectAtX_ = -1;
}
dc.PopScissor();
}
@@ -1250,12 +1265,38 @@ bool TextEdit::Touch(const TouchInput &touch) {
if (touch.flags & TouchInputFlags::DOWN) {
if (bounds_.Contains(touch.x, touch.y)) {
SetFocusedView(this, true);
int relativeX = touch.x - bounds_.x + scrollPos_;
selectAtX_ = relativeX;
return true;
}
}
return false;
}
void TextEdit::MoveLeft() {
if (caret_ > 0) {
u8_dec(text_.c_str(), &caret_);
}
}
void TextEdit::MoveRight() {
if (caret_ < (int)text_.size()) {
u8_inc(text_.c_str(), &caret_);
}
}
bool TextEdit::Backspace() {
if (caret_ > 0) {
int begCaret = caret_;
u8_dec(text_.c_str(), &begCaret);
undo_ = text_;
text_.erase(text_.begin() + begCaret, text_.begin() + caret_);
caret_--;
return true;
}
return false;
}
bool TextEdit::Key(const KeyInput &input) {
if (!HasFocus())
return false;
@@ -1268,10 +1309,10 @@ bool TextEdit::Key(const KeyInput &input) {
ctrlDown_ = true;
break;
case NKCODE_DPAD_LEFT: // ASCII left arrow
u8_dec(text_.c_str(), &caret_);
MoveLeft();
break;
case NKCODE_DPAD_RIGHT: // ASCII right arrow
u8_inc(text_.c_str(), &caret_);
MoveRight();
break;
case NKCODE_MOVE_HOME:
case NKCODE_PAGE_UP:
@@ -1291,12 +1332,7 @@ bool TextEdit::Key(const KeyInput &input) {
}
break;
case NKCODE_DEL:
if (caret_ > 0) {
int begCaret = caret_;
u8_dec(text_.c_str(), &begCaret);
undo_ = text_;
text_.erase(text_.begin() + begCaret, text_.begin() + caret_);
caret_--;
if (Backspace()) {
textChanged = true;
}
break;
+6 -2
View File
@@ -1104,12 +1104,15 @@ public:
bool Key(const KeyInput &key) override;
bool Touch(const TouchInput &touch) override;
bool Backspace();
void MoveLeft();
void MoveRight();
void InsertAtCaret(const char *text);
Event OnTextChange;
Event OnEnter;
private:
void InsertAtCaret(const char *text);
std::string text_;
std::string title_;
std::string undo_;
@@ -1122,6 +1125,7 @@ private:
bool ctrlDown_ = false; // TODO: Make some global mechanism for this.
bool passwordMasking_ = false;
int align_ = 0;
int selectAtX_ = -1; // on next draw, will select the character closest to this X coordinate. Used for touch selection.
// TODO: Selections
};
+12
View File
@@ -160,6 +160,18 @@ void ViewGroup::DeviceRestored(Draw::DrawContext *draw) {
}
}
bool ViewGroup::ReplaceSubview(View *view, View *newView) {
for (int i = 0; i < (int)views_.size(); i++) {
if (views_[i] == view) {
views_[i] = newView;
delete view;
return true;
}
}
delete newView;
return false;
}
void ViewGroup::Draw(UIContext &dc) {
if (hasDropShadow_) {
// Darken things behind.
+4
View File
@@ -51,6 +51,10 @@ public:
return view;
}
// Note: This deletes the old view, if found. Returns whether the view was found.
// If it fails, the newView is deleted.
bool ReplaceSubview(View *view, View *newView);
bool SetFocus() override;
bool SubviewFocused(View *view) override;
virtual void RemoveSubview(View *view);
+2
View File
@@ -182,6 +182,8 @@ static const ImageMeta imageIDs[] = {
{"I_UMD_VIDEO_ISO", false},
{"I_APP", false},
{"I_SHORTCUT", false},
{"I_KEYBOARD", false},
{"I_MOUSE", false},
};
static std::string PNGNameFromID(std::string_view id) {
+143 -9
View File
@@ -7,7 +7,7 @@
viewBox="0 0 158.74998 185.20831"
version="1.1"
id="svg1"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
sodipodi:docname="images.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@@ -24,13 +24,13 @@
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="1"
inkscape:cx="292.5"
inkscape:cy="350.5"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:zoom="2.8284271"
inkscape:cx="-1.2374369"
inkscape:cy="458.73552"
inkscape:window-width="3840"
inkscape:window-height="2071"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showgrid="false"
@@ -4538,7 +4538,137 @@
id="I_GEAR_STAR"
style="fill:#ececec;fill-opacity:1;stroke-width:0.0151106"
class="st0"
d="m 7.0939218,41.027272 -0.40566,1.30483 -1.30483,0.40566 1.1157,0.7891 -0.0176,1.36632 1.09502,-0.817 1.2945,0.43873 -0.43874,-1.2945 0.81701,-1.09502 -1.36633,0.0176 z m -2.1611,3.17293 c -0.10207,0 -0.191,0.0703 -0.21446,0.1695 l -0.1912,0.81287 c -0.32129,0.0745 -0.62282,0.20047 -0.89452,0.37 l -0.71004,-0.43873 c -0.0868,-0.0536 -0.19933,-0.0404 -0.2713,0.0315 l -0.37569,0.37569 c -0.0723,0.0723 -0.0853,0.18449 -0.0315,0.2713 l 0.43873,0.71055 c -0.16954,0.27187 -0.29604,0.5727 -0.37052,0.894 l -0.81235,0.19172 c -0.0993,0.0236 -0.1695,0.11216 -0.1695,0.21394 v 0.53175 c 0,0.10219 0.0701,0.19049 0.1695,0.21394 l 0.81235,0.19224 c 0.0745,0.32131 0.201,0.62215 0.37052,0.894 l -0.43873,0.71004 c -0.0536,0.0868 -0.0404,0.19984 0.0315,0.27181 l 0.37517,0.37517 c 0.0723,0.0723 0.18486,0.0853 0.27182,0.0315 l 0.71004,-0.43874 c 0.27171,0.16955 0.57323,0.29604 0.89452,0.37052 l 0.1912,0.81236 c 0.0235,0.0994 0.11239,0.1695 0.21446,0.1695 h 0.53175 c 0.10193,0 0.19049,-0.0701 0.21394,-0.1695 l 0.19172,-0.81236 c 0.32116,-0.0745 0.62276,-0.20097 0.89451,-0.37052 l 0.71004,0.43874 c 0.087,0.0537 0.19919,0.0407 0.2713,-0.0315 l 0.37569,-0.37517 c 0.0721,-0.0721 0.0852,-0.18447 0.0315,-0.2713 l -0.43925,-0.71055 c 0.16953,-0.27173 0.29603,-0.57282 0.37052,-0.894 l 0.81235,-0.19224 c 0.0996,-0.0236 0.1695,-0.11186 0.1695,-0.21394 v -0.53123 c -2e-5,-0.10206 -0.0701,-0.19099 -0.1695,-0.21446 l -0.81235,-0.1912 c -0.0745,-0.32129 -0.20099,-0.62267 -0.37052,-0.89452 l 0.43925,-0.71055 c 0.0537,-0.0871 0.0407,-0.19906 -0.0315,-0.2713 l -0.37569,-0.37517 c -0.0721,-0.0721 -0.18435,-0.0858 -0.2713,-0.032 l -0.71004,0.43873 c -0.27187,-0.16952 -0.57322,-0.29552 -0.89451,-0.37 l -0.19172,-0.81287 c -0.0235,-0.0993 -0.11201,-0.1695 -0.21394,-0.1695 z m 0.26561,1.83451 c 1.1236,0 2.03399,0.91063 2.03399,2.03399 0,1.12334 -0.91039,2.03398 -2.03399,2.03398 -1.12322,0 -2.03398,-0.91064 -2.03398,-2.03398 0,-1.12334 0.91076,-2.03399 2.03398,-2.03399 z m 0,1.16324 a 0.87043075,0.87043075 0 0 0 -0.87075,0.87075 0.87043075,0.87043075 0 0 0 0.87075,0.87023 0.87043075,0.87043075 0 0 0 0.87075,-0.87023 0.87043075,0.87043075 0 0 0 -0.87075,-0.87075 z" /></g><style
d="m 7.0939218,41.027272 -0.40566,1.30483 -1.30483,0.40566 1.1157,0.7891 -0.0176,1.36632 1.09502,-0.817 1.2945,0.43873 -0.43874,-1.2945 0.81701,-1.09502 -1.36633,0.0176 z m -2.1611,3.17293 c -0.10207,0 -0.191,0.0703 -0.21446,0.1695 l -0.1912,0.81287 c -0.32129,0.0745 -0.62282,0.20047 -0.89452,0.37 l -0.71004,-0.43873 c -0.0868,-0.0536 -0.19933,-0.0404 -0.2713,0.0315 l -0.37569,0.37569 c -0.0723,0.0723 -0.0853,0.18449 -0.0315,0.2713 l 0.43873,0.71055 c -0.16954,0.27187 -0.29604,0.5727 -0.37052,0.894 l -0.81235,0.19172 c -0.0993,0.0236 -0.1695,0.11216 -0.1695,0.21394 v 0.53175 c 0,0.10219 0.0701,0.19049 0.1695,0.21394 l 0.81235,0.19224 c 0.0745,0.32131 0.201,0.62215 0.37052,0.894 l -0.43873,0.71004 c -0.0536,0.0868 -0.0404,0.19984 0.0315,0.27181 l 0.37517,0.37517 c 0.0723,0.0723 0.18486,0.0853 0.27182,0.0315 l 0.71004,-0.43874 c 0.27171,0.16955 0.57323,0.29604 0.89452,0.37052 l 0.1912,0.81236 c 0.0235,0.0994 0.11239,0.1695 0.21446,0.1695 h 0.53175 c 0.10193,0 0.19049,-0.0701 0.21394,-0.1695 l 0.19172,-0.81236 c 0.32116,-0.0745 0.62276,-0.20097 0.89451,-0.37052 l 0.71004,0.43874 c 0.087,0.0537 0.19919,0.0407 0.2713,-0.0315 l 0.37569,-0.37517 c 0.0721,-0.0721 0.0852,-0.18447 0.0315,-0.2713 l -0.43925,-0.71055 c 0.16953,-0.27173 0.29603,-0.57282 0.37052,-0.894 l 0.81235,-0.19224 c 0.0996,-0.0236 0.1695,-0.11186 0.1695,-0.21394 v -0.53123 c -2e-5,-0.10206 -0.0701,-0.19099 -0.1695,-0.21446 l -0.81235,-0.1912 c -0.0745,-0.32129 -0.20099,-0.62267 -0.37052,-0.89452 l 0.43925,-0.71055 c 0.0537,-0.0871 0.0407,-0.19906 -0.0315,-0.2713 l -0.37569,-0.37517 c -0.0721,-0.0721 -0.18435,-0.0858 -0.2713,-0.032 l -0.71004,0.43873 c -0.27187,-0.16952 -0.57322,-0.29552 -0.89451,-0.37 l -0.19172,-0.81287 c -0.0235,-0.0993 -0.11201,-0.1695 -0.21394,-0.1695 z m 0.26561,1.83451 c 1.1236,0 2.03399,0.91063 2.03399,2.03399 0,1.12334 -0.91039,2.03398 -2.03399,2.03398 -1.12322,0 -2.03398,-0.91064 -2.03398,-2.03398 0,-1.12334 0.91076,-2.03399 2.03398,-2.03399 z m 0,1.16324 a 0.87043075,0.87043075 0 0 0 -0.87075,0.87075 0.87043075,0.87043075 0 0 0 0.87075,0.87023 0.87043075,0.87043075 0 0 0 0.87075,-0.87023 0.87043075,0.87043075 0 0 0 -0.87075,-0.87075 z" /><g
id="I_KEYBOARD"
transform="matrix(0.0238205,0,0,0.0238205,45.790606,145.52992)"
style="fill:#ffffff;fill-opacity:1;stroke:none">
<path
class="st0"
d="M 459.576,99.307 H 52.423 C 23.524,99.307 0,122.837 0,151.736 v 192.879 c 0,37.536 30.537,68.078 68.068,68.078 H 443.93 c 37.532,0 68.069,-30.542 68.069,-68.078 V 151.736 C 512,122.837 488.475,99.307 459.576,99.307 Z m 25.939,245.308 c 0,22.934 -18.655,41.589 -41.584,41.589 H 68.068 c -22.929,0 -41.584,-18.655 -41.584,-41.589 V 151.736 c 0,-14.306 11.638,-25.938 25.938,-25.938 h 407.154 c 14.301,0 25.938,11.633 25.938,25.938 v 192.879 z"
id="path1"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="189.79201"
y="233.929"
class="st0"
width="44.138"
height="44.141998"
id="rect1"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="256.00201"
y="233.929"
class="st0"
width="44.133999"
height="44.141998"
id="rect2-4"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="322.207"
y="233.929"
class="st0"
width="44.138"
height="44.141998"
id="rect3-8"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="410.48401"
y="300.13901"
class="st0"
width="44.133999"
height="44.133999"
id="rect4-8"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="189.79201"
y="167.729"
class="st0"
width="44.138"
height="44.133999"
id="rect5-2"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="123.587"
y="233.929"
class="st0"
width="44.138"
height="44.141998"
id="rect6-4"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="123.587"
y="167.729"
class="st0"
width="44.138"
height="44.133999"
id="rect7-5"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="57.382"
y="300.13901"
class="st0"
width="44.133999"
height="44.133999"
id="rect8-5"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="57.382"
y="233.929"
class="st0"
width="44.133999"
height="44.141998"
id="rect9"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="57.382"
y="167.729"
class="st0"
width="44.133999"
height="44.133999"
id="rect10"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="256.00201"
y="167.729"
class="st0"
width="44.133999"
height="44.133999"
id="rect11"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="322.207"
y="167.729"
class="st0"
width="44.138"
height="44.133999"
id="rect12"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="123.587"
y="300.13901"
class="st0"
width="264.82501"
height="44.133999"
id="rect13"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
x="388.41199"
y="167.729"
class="st0"
width="66.205002"
height="110.343"
id="rect14"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
</g><g
id="I_MOUSE"
transform="matrix(0.34885654,0,0,0.34885654,57.606248,145.05802)"
style="fill:#ffffff;fill-opacity:1;stroke:none"><g
id="icomoon-ignore"
style="fill:#ffffff;fill-opacity:1;stroke:none" /><path
d="M 16.533,8.562 V 6.915 c 0,-0.487 1.029,-1.131 1.855,-1.649 1.184,-0.741 2.41,-1.509 2.41,-2.627 V 0.006 h -1.066 v 2.633 c 0,0.527 -1.058,1.19 -1.909,1.723 -1.158,0.725 -2.356,1.475 -2.356,2.552 V 8.561 C 11.3,8.829 8.003,12.187 8.003,16.3 v 7.927 c 0,4.288 3.58,7.765 7.997,7.765 4.417,0 7.997,-3.477 7.997,-7.765 V 16.3 c 0,-4.114 -3.297,-7.472 -7.464,-7.739 z m 6.398,7.739 v 0.765 H 16.533 V 9.628 c 3.572,0.265 6.398,3.153 6.398,6.673 z m -13.862,0 c 0,-3.52 2.825,-6.408 6.398,-6.673 v 7.438 H 9.069 Z M 16,30.927 c -3.821,0 -6.931,-3.005 -6.931,-6.699 V 18.132 H 22.93 v 6.096 c 0,3.694 -3.109,6.699 -6.931,6.699 z"
fill="#000000"
id="path1-15"
style="fill:#ffffff;fill-opacity:1;stroke:none" /></g></g><style
type="text/css"
id="style1">
.st0{fill:#000000;}
@@ -4565,4 +4695,8 @@
<![CDATA[
.st0{fill:#000000;}
]]>
</style><style
type="text/css"
id="style1-09">
.st0{fill:#000000;}
</style></svg>

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 256 KiB