mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Merge pull request #21630 from hrydgard/break-out-search
Refactor type-to-search code for reuse, use in cheats dialog
This commit is contained in:
15 files changed
+293
-247
No files matched your search
@@ -2903,7 +2903,6 @@ set(NativeAssets
|
||||
assets/Roboto_Condensed-Bold.ttf
|
||||
assets/Roboto_Condensed-Italic.ttf
|
||||
assets/Inconsolata-Regular.ttf
|
||||
assets/7z.png
|
||||
assets/compat.ini
|
||||
assets/adhoc-servers.json
|
||||
assets/infra-dns.json
|
||||
@@ -2911,8 +2910,6 @@ set(NativeAssets
|
||||
assets/langregion.ini
|
||||
assets/ppge_atlas.zim
|
||||
assets/ppge_atlas.meta
|
||||
assets/rargray.png
|
||||
assets/zip.png
|
||||
assets/sfx_back.wav
|
||||
assets/sfx_confirm.wav
|
||||
assets/sfx_select.wav
|
||||
|
||||
@@ -340,7 +340,7 @@ bool ChoiceStrip::Key(const KeyInput &input) {
|
||||
if (selected_ > 0) {
|
||||
SetSelection(selected_ - 1, true);
|
||||
} else if (!choices_.empty()) {
|
||||
SetSelection(choices_.size() - 1, true);
|
||||
SetSelection((int)choices_.size() - 1, true);
|
||||
}
|
||||
} else {
|
||||
if (selected_ < (int)choices_.size() - 1) {
|
||||
|
||||
+29
-3
@@ -86,6 +86,15 @@ void CwCheatScreen::BeforeCreateViews() {
|
||||
TryLoadCheatInfo(); // in case the info is already in cache.
|
||||
}
|
||||
|
||||
bool CwCheatScreen::key(const KeyInput &input) {
|
||||
if (search_.Key(cheatList_, input)) {
|
||||
// This will eat up the ESC key, which is used to cancel searches.
|
||||
return true;
|
||||
}
|
||||
|
||||
return UITwoPaneBaseDialogScreen::key(input);
|
||||
}
|
||||
|
||||
void CwCheatScreen::CreateSettingsViews(UI::ViewGroup *leftColumn) {
|
||||
using namespace UI;
|
||||
auto cw = GetI18NCategory(I18NCat::CWCHEATS);
|
||||
@@ -118,7 +127,11 @@ void CwCheatScreen::CreateContentViews(UI::ViewGroup *parent) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
|
||||
UI::ScrollView *rightScroll = parent->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 0.5f)));
|
||||
UI::LinearLayout *rightSide = parent->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 0.5f)));
|
||||
search_.searchFilter.clear();
|
||||
search_.searchBar = rightSide->Add(new SearchBar(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
|
||||
|
||||
UI::ScrollView *rightScroll = rightSide->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)));
|
||||
rightScroll->SetTag("CwCheats");
|
||||
rightScroll->RememberPosition(&g_Config.fCwCheatScrollPosition);
|
||||
|
||||
@@ -126,6 +139,8 @@ void CwCheatScreen::CreateContentViews(UI::ViewGroup *parent) {
|
||||
rightColumn->SetSpacing(0.0f);
|
||||
rightScroll->Add(rightColumn);
|
||||
|
||||
cheatList_ = rightColumn;
|
||||
|
||||
if (!errorMessage_.empty()) {
|
||||
rightColumn->Add(new NoticeView(errorLevel_, errorMessage_, errorDetails_));
|
||||
rightColumn->Add(new Spacer(8.0f));
|
||||
@@ -134,6 +149,7 @@ void CwCheatScreen::CreateContentViews(UI::ViewGroup *parent) {
|
||||
rightColumn->Add(new ItemHeader(cw->T("Cheats")));
|
||||
|
||||
bool prevIsTitle = false;
|
||||
View *prev = nullptr;
|
||||
for (size_t i = 0; i < fileInfo_.size(); ++i) {
|
||||
std::string_view text;
|
||||
if (fileInfo_[i].IsTitle(&text)) {
|
||||
@@ -141,17 +157,20 @@ void CwCheatScreen::CreateContentViews(UI::ViewGroup *parent) {
|
||||
TextView *titleView = rightColumn->Add(new TextView(text, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, UI::Margins(8, 8, 8, 0))));
|
||||
titleView->SetTextSize(UI::TextSize::Big);
|
||||
prevIsTitle = true;
|
||||
prev = nullptr;
|
||||
} else if (fileInfo_[i].IsPostComment(&text)) {
|
||||
rightColumn->Add(new SettingHint(text, nullptr));
|
||||
rightColumn->Add(new SettingHint(text, prev));
|
||||
prevIsTitle = false;
|
||||
} else {
|
||||
// Regular cheat code.
|
||||
if (!prevIsTitle) {
|
||||
rightColumn->Add(new Spacer(8.0f));
|
||||
}
|
||||
rightColumn->Add(new CheckBox(&fileInfo_[i].enabled, fileInfo_[i].name))->OnClick.Add([=](UI::EventParams &) {
|
||||
CheckBox *checkBox = rightColumn->Add(new CheckBox(&fileInfo_[i].enabled, fileInfo_[i].name));
|
||||
checkBox->OnClick.Add([=](UI::EventParams &) {
|
||||
OnCheckBox((int)i);
|
||||
});
|
||||
prev = checkBox;
|
||||
prevIsTitle = false;
|
||||
}
|
||||
}
|
||||
@@ -456,6 +475,13 @@ bool CwCheatScreen::RebuildCheatFile(int index) {
|
||||
}
|
||||
fclose(out);
|
||||
|
||||
// Don't force an auto-reload, though.
|
||||
std::string str;
|
||||
if (File::ReadTextFileToString(engine_->CheatFilename(), &str)) {
|
||||
uint64_t newHash = XXH3_64bits(str.c_str(), str.size());
|
||||
fileCheckHash_ = newHash;
|
||||
}
|
||||
|
||||
// Cheats will need to be reparsed now.
|
||||
g_Config.bReloadCheats = true;
|
||||
return true;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Common/UI/Context.h"
|
||||
#include "UI/BaseScreens.h"
|
||||
#include "UI/SimpleDialogScreen.h"
|
||||
#include "UI/MiscViews.h"
|
||||
|
||||
struct CheatFileInfo;
|
||||
class CWCheatEngine;
|
||||
@@ -44,6 +45,7 @@ public:
|
||||
void OnDisableAll(UI::EventParams ¶ms);
|
||||
|
||||
void update() override;
|
||||
bool key(const KeyInput &input) override;
|
||||
void onFinish(DialogResult result) override;
|
||||
|
||||
const char *tag() const override { return "CwCheat"; }
|
||||
@@ -73,4 +75,7 @@ private:
|
||||
std::string errorMessage_;
|
||||
NoticeLevel errorLevel_ = NoticeLevel::ERROR;
|
||||
std::string errorDetails_;
|
||||
|
||||
UI::ViewGroup *cheatList_ = nullptr;
|
||||
ViewSearch search_;
|
||||
};
|
||||
+22
-168
@@ -235,6 +235,9 @@ void GameButton::Draw(UIContext &dc) {
|
||||
case IdentifiedFileType::PPSSPP_SAVESTATE:
|
||||
case IdentifiedFileType::ERROR_IDENTIFYING:
|
||||
case IdentifiedFileType::UNKNOWN_BIN: imageIcon = ImageID("I_FILE"); break;
|
||||
case IdentifiedFileType::ARCHIVE_ZIP: imageIcon = ImageID("I_ARCHIVE_ZIP"); drawBackground = false; break;
|
||||
case IdentifiedFileType::ARCHIVE_7Z: imageIcon = ImageID("I_ARCHIVE_7Z"); drawBackground = false; break;
|
||||
case IdentifiedFileType::ARCHIVE_RAR: imageIcon = ImageID("I_ARCHIVE_RAR"); drawBackground = false; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -462,7 +465,7 @@ std::string GameButton::DescribeText() const {
|
||||
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO))
|
||||
return "...";
|
||||
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
|
||||
return ApplySafeSubstitutions(u->T("%1 button"), ginfo->GetTitle());
|
||||
return ginfo->GetTitle();
|
||||
}
|
||||
|
||||
class DirButton : public UI::Button {
|
||||
@@ -486,6 +489,10 @@ public:
|
||||
pinned_ = pin;
|
||||
}
|
||||
|
||||
std::string DescribeText() const {
|
||||
return std::string(Button::GetText()); // From Button
|
||||
}
|
||||
|
||||
private:
|
||||
Path path_;
|
||||
bool gridStyle_;
|
||||
@@ -551,120 +558,13 @@ bool GameBrowser::Key(const KeyInput &input) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only one is visible at a time, so we can just grab all Char input.
|
||||
if (input.flags & KeyInputFlags::CHAR) {
|
||||
const int unichar = input.keyCode;
|
||||
if (unichar >= 0x20) {
|
||||
// TODO: Save focus state here.
|
||||
|
||||
// Insert it! (todo: do it with a string insert)
|
||||
char buf[8];
|
||||
buf[u8_wc_toutf8(buf, unichar)] = '\0';
|
||||
searchFilter_ += buf;
|
||||
ApplySearchFilter(true);
|
||||
retval = true;
|
||||
}
|
||||
} else if (input.flags & KeyInputFlags::DOWN) {
|
||||
if (input.keyCode == NKCODE_DEL) {
|
||||
if (!searchFilter_.empty()) {
|
||||
searchFilter_.pop_back();
|
||||
ApplySearchFilter(true);
|
||||
retval = true;
|
||||
if (searchFilter_.empty()) {
|
||||
// TODO: Restore focus state here.
|
||||
UI::EnableFocusMovement(false);
|
||||
}
|
||||
} else {
|
||||
// Empty search filter. Navigate upwards on backspace?
|
||||
}
|
||||
} else if (!searchFilter_.empty() && input.keyCode == NKCODE_ESCAPE) {
|
||||
searchFilter_.clear();
|
||||
ApplySearchFilter(false);
|
||||
retval = true;
|
||||
|
||||
// TODO: Restore focus state here.
|
||||
UI::EnableFocusMovement(false);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
return search_.Key(gameList_, input);
|
||||
}
|
||||
|
||||
void GameBrowser::SetSearchFilter(const std::string &filter, bool setKeyboardFocus) {
|
||||
searchFilter_ = filter;
|
||||
search_.searchFilter = filter;
|
||||
// We don't refresh because game info loads asynchronously anyway.
|
||||
ApplySearchFilter(setKeyboardFocus);
|
||||
}
|
||||
|
||||
void GameBrowser::ApplySearchFilter(bool setKeyboardFocus) {
|
||||
if (searchBar_) {
|
||||
searchBar_->SetSearchFilter(searchFilter_);
|
||||
searchBar_->SetVisibility(searchFilter_.empty() ? UI::V_GONE : UI::V_VISIBLE);
|
||||
}
|
||||
|
||||
if (searchFilter_.empty() && searchStates_.empty()) {
|
||||
// We haven't hidden anything, and we're not searching, so do nothing.
|
||||
searchPending_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string filter = NormalizeForSearch(searchFilter_);
|
||||
|
||||
searchPending_ = false;
|
||||
// By default, everything is matching.
|
||||
searchStates_.resize(gameList_->GetNumSubviews(), SearchState::MATCH);
|
||||
|
||||
if (filter.empty()) {
|
||||
// Just quickly mark anything we hid as visible again.
|
||||
for (int i = 0; i < gameList_->GetNumSubviews(); ++i) {
|
||||
UI::View *v = gameList_->GetViewByIndex(i);
|
||||
if (searchStates_[i] != SearchState::MATCH)
|
||||
v->SetVisibility(UI::V_VISIBLE);
|
||||
}
|
||||
|
||||
searchStates_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
View *firstMatch = nullptr;
|
||||
|
||||
for (int i = 0; i < gameList_->GetNumSubviews(); ++i) {
|
||||
UI::View *v = gameList_->GetViewByIndex(i);
|
||||
std::string label = v->DescribeText();
|
||||
// TODO: Maybe we should just save the gameButtons list, though nice to search dirs too?
|
||||
// This is a bit of a hack to recognize a pending game title.
|
||||
if (label == "...") {
|
||||
searchPending_ = true;
|
||||
// Hide anything pending while, we'll pop-in search results as they match.
|
||||
// Note: we leave it at MATCH if gone before, so we don't show it again.
|
||||
if (v->GetVisibility() == UI::V_VISIBLE) {
|
||||
if (searchStates_[i] == SearchState::MATCH)
|
||||
v->SetVisibility(UI::V_GONE);
|
||||
searchStates_[i] = SearchState::PENDING;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
label = NormalizeForSearch(label);
|
||||
bool match = v->CanBeFocused() && label.find(filter) != label.npos;
|
||||
if (match && !firstMatch) {
|
||||
firstMatch = v;
|
||||
}
|
||||
if (match && searchStates_[i] != SearchState::MATCH) {
|
||||
// It was previously visible and force hidden, so show it again.
|
||||
v->SetVisibility(UI::V_VISIBLE);
|
||||
searchStates_[i] = SearchState::MATCH;
|
||||
} else if (!match && searchStates_[i] == SearchState::MATCH && v->GetVisibility() == UI::V_VISIBLE) {
|
||||
v->SetVisibility(UI::V_GONE);
|
||||
searchStates_[i] = SearchState::MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstMatch) {
|
||||
if (setKeyboardFocus) {
|
||||
UI::EnableFocusMovement(true);
|
||||
}
|
||||
UI::SetFocusedView(firstMatch);
|
||||
}
|
||||
search_.ApplySearchFilter(gameList_, setKeyboardFocus);
|
||||
}
|
||||
|
||||
void GameBrowser::LayoutChange(UI::EventParams &e) {
|
||||
@@ -762,8 +662,8 @@ void GameBrowser::Update() {
|
||||
Refresh();
|
||||
refreshPending_ = false;
|
||||
}
|
||||
if (searchPending_) {
|
||||
ApplySearchFilter(false);
|
||||
if (search_.searchPending) {
|
||||
search_.ApplySearchFilter(gameList_, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,52 +701,9 @@ void GameBrowser::Draw(UIContext &dc) {
|
||||
}
|
||||
}
|
||||
|
||||
void SearchBar::Draw(UIContext &dc) {
|
||||
using namespace UI;
|
||||
|
||||
dc.FillRect(dc.GetTheme().itemStyle.background, bounds_);
|
||||
|
||||
const ImageID searchIcon = ImageID("I_SEARCH");
|
||||
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(searchIcon);
|
||||
int leftMargin = 10;
|
||||
if (image) {
|
||||
dc.Draw()->DrawImage(searchIcon, bounds_.x + leftMargin, bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
leftMargin += image->w + 10;
|
||||
}
|
||||
dc.DrawText(searchFilter_, bounds_.x + leftMargin, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
}
|
||||
|
||||
void SearchBar::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0;
|
||||
h = 0;
|
||||
const ImageID searchIcon = ImageID("I_SEARCH");
|
||||
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, searchFilter_, &w, &h);
|
||||
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(searchIcon);
|
||||
if (image) {
|
||||
w += image->w + 10;
|
||||
h = std::max(h, (float)image->h);
|
||||
}
|
||||
w += 20; // Padding
|
||||
h += 24;
|
||||
}
|
||||
|
||||
bool SearchBar::Touch(const TouchInput &input) {
|
||||
bool retval = UI::InertView::Touch(input);
|
||||
// Search bar has a simple touch-to-cancel functionality,
|
||||
// for the user to be able to get out of searches without knowing ESC (or backspacing the whole search string).
|
||||
if (input.flags & TouchInputFlags::DOWN) {
|
||||
if (bounds_.Contains(input.x, input.y)) {
|
||||
UI::EventParams params{this};
|
||||
OnCancel.Trigger(params);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void GameBrowser::SetSearchBar(SearchBar *searchBar) {
|
||||
searchBar_ = searchBar;
|
||||
searchBar_->OnCancel.Add([this](UI::EventParams &) {
|
||||
search_.searchBar = searchBar;
|
||||
search_.searchBar->OnCancel.Add([this](UI::EventParams &) {
|
||||
SetSearchFilter("", false);
|
||||
});
|
||||
}
|
||||
@@ -880,7 +737,7 @@ void GameBrowser::Refresh() {
|
||||
|
||||
// Kill all the contents
|
||||
Clear();
|
||||
searchStates_.clear();
|
||||
search_.searchStates.clear();
|
||||
|
||||
Add(new Spacer(1.0f));
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
@@ -1020,21 +877,18 @@ void GameBrowser::Refresh() {
|
||||
gameButtons.push_back(new GameButton(fileInfo[i].fullName, *gridStyle_, new UI::LinearLayoutParams(*gridStyle_ == true ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT)));
|
||||
}
|
||||
}
|
||||
// Put RAR/ZIP files at the end to get them out of the way. They're only shown so that people
|
||||
// can click them and get an explanation that they need to unpack them. This is necessary due
|
||||
// to a flood of support email...
|
||||
|
||||
// Put RAR/ZIP files at the end to get them out of the way.
|
||||
// We do support unpacking some of them automatically.
|
||||
if (browseFlags_ & BrowseFlags::ARCHIVES) {
|
||||
fileInfo.clear();
|
||||
path_.GetListing(fileInfo, "zip:rar:r01:7z:");
|
||||
path_.GetListing(fileInfo, "zip:rar:r00:r01:7z:");
|
||||
if (!fileInfo.empty()) {
|
||||
UI::LinearLayout *zl = new UI::LinearLayoutList(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
zl->SetSpacing(4.0f);
|
||||
Add(zl);
|
||||
for (size_t i = 0; i < fileInfo.size(); i++) {
|
||||
if (!fileInfo[i].isDirectory) {
|
||||
GameButton *b = zl->Add(new GameButton(fileInfo[i].fullName, false, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)));
|
||||
b->OnClick.Handle(this, &GameBrowser::GameButtonClick);
|
||||
GameButton *b = new GameButton(fileInfo[i].fullName, *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT));
|
||||
b->SetHoldEnabled(false);
|
||||
gameButtons.push_back(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-27
@@ -6,6 +6,7 @@
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/File/PathBrowser.h"
|
||||
#include "UI/MiscViews.h"
|
||||
|
||||
enum GameBrowserFlags {
|
||||
FLAG_HOMEBREWSTOREBUTTON = 1
|
||||
@@ -23,22 +24,6 @@ enum class BrowseFlags {
|
||||
};
|
||||
ENUM_CLASS_BITOPS(BrowseFlags);
|
||||
|
||||
class SearchBar : public UI::InertView {
|
||||
public:
|
||||
SearchBar(UI::LayoutParams *params) : UI::InertView(params) { SetVisibility(UI::Visibility::V_GONE); }
|
||||
void Draw(UIContext &dc) override;
|
||||
|
||||
bool Touch(const TouchInput &input) override;
|
||||
void SetSearchFilter(std::string_view filter) {
|
||||
searchFilter_ = filter;
|
||||
}
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
|
||||
UI::Event OnCancel;
|
||||
private:
|
||||
std::string searchFilter_ = "N/A";
|
||||
};
|
||||
|
||||
class GameBrowser : public UI::LinearLayout {
|
||||
public:
|
||||
GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool portrait, bool *gridStyle, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams = nullptr);
|
||||
@@ -66,7 +51,6 @@ protected:
|
||||
virtual bool DisplayTopBar();
|
||||
virtual bool HasSpecialFiles(std::vector<Path> &filenames);
|
||||
virtual Path HomePath();
|
||||
void ApplySearchFilter(bool setKeyboardFocus);
|
||||
|
||||
void Refresh();
|
||||
|
||||
@@ -90,24 +74,17 @@ private:
|
||||
void OnRecentClear(UI::EventParams &e);
|
||||
void OnHomebrewStore(UI::EventParams &e);
|
||||
|
||||
enum class SearchState {
|
||||
MATCH,
|
||||
MISMATCH,
|
||||
PENDING,
|
||||
};
|
||||
|
||||
UI::ViewGroup *gameList_ = nullptr;
|
||||
PathBrowser path_;
|
||||
SearchBar *searchBar_ = nullptr;
|
||||
bool *gridStyle_ = nullptr;
|
||||
BrowseFlags browseFlags_;
|
||||
std::string lastText_;
|
||||
std::string lastLink_;
|
||||
std::string searchFilter_;
|
||||
std::vector<SearchState> searchStates_;
|
||||
|
||||
ViewSearch search_{};
|
||||
|
||||
Path focusGamePath_;
|
||||
bool listingPending_ = false;
|
||||
bool searchPending_ = false;
|
||||
bool refreshPending_ = false;
|
||||
float lastScale_ = 1.0f;
|
||||
bool lastLayoutWasGrid_ = true;
|
||||
|
||||
+1
-20
@@ -882,26 +882,7 @@ handleELF:
|
||||
|
||||
case IdentifiedFileType::ARCHIVE_ZIP:
|
||||
info_->title = info_->GetFilePath().GetFilename();
|
||||
if (flags_ & GameInfoFlags::ICON) {
|
||||
ReadVFSToString("zip.png", &info_->icon.data, &info_->lock);
|
||||
info_->icon.dataLoaded = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case IdentifiedFileType::ARCHIVE_RAR:
|
||||
info_->title = info_->GetFilePath().GetFilename();
|
||||
if (flags_ & GameInfoFlags::ICON) {
|
||||
ReadVFSToString("rargray.png", &info_->icon.data, &info_->lock);
|
||||
info_->icon.dataLoaded = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case IdentifiedFileType::ARCHIVE_7Z:
|
||||
info_->title = info_->GetFilePath().GetFilename();
|
||||
if (flags_ & GameInfoFlags::ICON) {
|
||||
ReadVFSToString("7z.png", &info_->icon.data, &info_->lock);
|
||||
info_->icon.dataLoaded = true;
|
||||
}
|
||||
info_->icon.dataLoaded = true;
|
||||
break;
|
||||
|
||||
case IdentifiedFileType::NORMAL_DIRECTORY:
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Math/curves.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/UI/Root.h"
|
||||
#include "UI/MiscViews.h"
|
||||
#include "UI/GameInfoCache.h"
|
||||
#include "Common/UI/PopupScreens.h"
|
||||
@@ -307,3 +309,166 @@ void SettingHint::Draw(UIContext &dc) {
|
||||
dc.FillRect(style.background, bounds_);
|
||||
UI::TextView::Draw(dc);
|
||||
}
|
||||
|
||||
void SearchBar::Draw(UIContext &dc) {
|
||||
using namespace UI;
|
||||
|
||||
dc.FillRect(dc.GetTheme().itemStyle.background, bounds_);
|
||||
|
||||
const ImageID searchIcon = ImageID("I_SEARCH");
|
||||
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(searchIcon);
|
||||
int leftMargin = 10;
|
||||
if (image) {
|
||||
dc.Draw()->DrawImage(searchIcon, bounds_.x + leftMargin, bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
leftMargin += image->w + 10;
|
||||
}
|
||||
dc.DrawText(searchFilter_, bounds_.x + leftMargin, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
}
|
||||
|
||||
void SearchBar::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0;
|
||||
h = 0;
|
||||
const ImageID searchIcon = ImageID("I_SEARCH");
|
||||
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, searchFilter_, &w, &h);
|
||||
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(searchIcon);
|
||||
if (image) {
|
||||
w += image->w + 10;
|
||||
h = std::max(h, (float)image->h);
|
||||
}
|
||||
w += 20; // Padding
|
||||
h += 24;
|
||||
}
|
||||
|
||||
bool SearchBar::Touch(const TouchInput &input) {
|
||||
bool retval = UI::InertView::Touch(input);
|
||||
// Search bar has a simple touch-to-cancel functionality,
|
||||
// for the user to be able to get out of searches without knowing ESC (or backspacing the whole search string).
|
||||
if (input.flags & TouchInputFlags::DOWN) {
|
||||
if (bounds_.Contains(input.x, input.y)) {
|
||||
UI::EventParams params{this};
|
||||
OnCancel.Trigger(params);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ViewSearch::ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus) {
|
||||
if (searchBar) {
|
||||
searchBar->SetSearchFilter(searchFilter);
|
||||
searchBar->SetVisibility(searchFilter.empty() ? UI::V_GONE : UI::V_VISIBLE);
|
||||
}
|
||||
|
||||
if (searchFilter.empty() && searchStates.empty()) {
|
||||
// We haven't hidden anything, and we're not searching, so do nothing.
|
||||
searchPending = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string filter = NormalizeForSearch(searchFilter);
|
||||
|
||||
searchPending = false;
|
||||
// By default, everything is matching.
|
||||
searchStates.resize(viewGroup->GetNumSubviews(), SearchState::MATCH);
|
||||
if (filter.empty()) {
|
||||
// Just quickly mark anything we hid as visible again.
|
||||
for (int i = 0; i < viewGroup->GetNumSubviews(); ++i) {
|
||||
UI::View *v = viewGroup->GetViewByIndex(i);
|
||||
if (searchStates[i] != SearchState::MATCH)
|
||||
v->SetVisibility(UI::V_VISIBLE);
|
||||
}
|
||||
|
||||
searchStates.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
UI::View *firstMatch = nullptr;
|
||||
|
||||
for (int i = 0; i < viewGroup->GetNumSubviews(); ++i) {
|
||||
UI::View *v = viewGroup->GetViewByIndex(i);
|
||||
std::string label = v->DescribeText();
|
||||
// This is a bit of a hack to recognize a pending game title.
|
||||
if (label == "...") {
|
||||
searchPending = true;
|
||||
// Hide anything pending while, we'll pop-in search results as they match.
|
||||
// Note: we leave it at MATCH if gone before, so we don't show it again.
|
||||
if (v->GetVisibility() == UI::V_VISIBLE) {
|
||||
if (searchStates[i] == SearchState::MATCH)
|
||||
v->SetVisibility(UI::V_GONE);
|
||||
searchStates[i] = SearchState::PENDING;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
label = NormalizeForSearch(label);
|
||||
bool match = v->CanBeFocused() && label.find(filter) != label.npos;
|
||||
if (match && !firstMatch) {
|
||||
firstMatch = v;
|
||||
}
|
||||
if (match && searchStates[i] != SearchState::MATCH) {
|
||||
// It was previously visible and force hidden, so show it again.
|
||||
v->SetVisibility(UI::V_VISIBLE);
|
||||
searchStates[i] = SearchState::MATCH;
|
||||
} else if (!match && searchStates[i] == SearchState::MATCH && v->GetVisibility() == UI::V_VISIBLE) {
|
||||
v->SetVisibility(UI::V_GONE);
|
||||
searchStates[i] = SearchState::MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstMatch) {
|
||||
if (setKeyboardFocus) {
|
||||
UI::EnableFocusMovement(true);
|
||||
}
|
||||
UI::SetFocusedView(firstMatch);
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewSearch::Key(UI::ViewGroup *viewGroup, const KeyInput &input) {
|
||||
bool retval = false;
|
||||
// Only one is visible at a time, so we can just grab all Char input.
|
||||
if (input.flags & KeyInputFlags::CHAR) {
|
||||
const int unichar = input.keyCode;
|
||||
if (unichar >= 0x20 && unichar != 127) { // 127 gets produced from Ctrl+Backspace on Windows for some reason.
|
||||
// TODO: Save focus state here.
|
||||
|
||||
// Insert it! (todo: do it with a string insert)
|
||||
char buf[8];
|
||||
buf[u8_wc_toutf8(buf, unichar)] = '\0';
|
||||
searchFilter += buf;
|
||||
ApplySearchFilter(viewGroup, true);
|
||||
retval = true;
|
||||
}
|
||||
} else if (input.flags & KeyInputFlags::DOWN) {
|
||||
if (input.keyCode == NKCODE_DEL) {
|
||||
if (!searchFilter.empty()) {
|
||||
if (input.flags & KeyInputFlags::MOD_CTRL) {
|
||||
// Ctrl+Backspace deletes the last word. Delete until the last space.
|
||||
size_t pos = searchFilter.find_last_of(' ');
|
||||
if (pos != searchFilter.npos) {
|
||||
searchFilter.erase(pos);
|
||||
} else {
|
||||
searchFilter.clear();
|
||||
}
|
||||
} else {
|
||||
searchFilter.pop_back();
|
||||
}
|
||||
ApplySearchFilter(viewGroup, true);
|
||||
retval = true;
|
||||
if (searchFilter.empty()) {
|
||||
// TODO: Restore focus state here.
|
||||
UI::EnableFocusMovement(false);
|
||||
}
|
||||
} else {
|
||||
// Empty search filter. Navigate upwards on backspace?
|
||||
}
|
||||
} else if (!searchFilter.empty() && input.keyCode == NKCODE_ESCAPE) {
|
||||
searchFilter.clear();
|
||||
ApplySearchFilter(viewGroup, false);
|
||||
retval = true;
|
||||
|
||||
// TODO: Restore focus state here.
|
||||
UI::EnableFocusMovement(false);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -93,9 +93,42 @@ protected:
|
||||
class SettingHint : public UI::TextView {
|
||||
public:
|
||||
SettingHint(std::string_view text, UI::View *setting);
|
||||
std::string DescribeText() const override { return setting_ ? setting_->DescribeText() : ""; } // So that descriptions show up in searches under their parent views
|
||||
void Draw(UIContext &dc) override;
|
||||
private:
|
||||
UI::View *setting_;
|
||||
};
|
||||
|
||||
void AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool text);
|
||||
|
||||
class SearchBar : public UI::InertView {
|
||||
public:
|
||||
SearchBar(UI::LayoutParams *params) : UI::InertView(params) { SetVisibility(UI::Visibility::V_GONE); }
|
||||
void Draw(UIContext &dc) override;
|
||||
|
||||
bool Touch(const TouchInput &input) override;
|
||||
void SetSearchFilter(std::string_view filter) {
|
||||
searchFilter_ = filter;
|
||||
}
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
|
||||
UI::Event OnCancel;
|
||||
private:
|
||||
std::string searchFilter_ = "N/A";
|
||||
};
|
||||
|
||||
enum class SearchState {
|
||||
MATCH,
|
||||
MISMATCH,
|
||||
PENDING,
|
||||
};
|
||||
|
||||
struct ViewSearch {
|
||||
SearchBar *searchBar;
|
||||
std::string searchFilter;
|
||||
std::vector<SearchState> searchStates;
|
||||
bool searchPending;
|
||||
|
||||
void ApplySearchFilter(UI::ViewGroup *viewGroup, bool setKeyboardFocus);
|
||||
bool Key(UI::ViewGroup *viewGroup, const KeyInput &input);
|
||||
};
|
||||
@@ -194,6 +194,9 @@ static const ImageMeta g_uiImageIDs[] = {
|
||||
{"I_RADIO_SELECTED", false},
|
||||
{"I_EDIT_TEXT", false},
|
||||
{"I_SEND", false},
|
||||
{"I_ARCHIVE_ZIP", false},
|
||||
{"I_ARCHIVE_7Z", false},
|
||||
{"I_ARCHIVE_RAR", false},
|
||||
};
|
||||
|
||||
static std::string PNGNameFromID(std::string_view id) {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
mkdir -p assets
|
||||
cp ../assets/7z.png assets/
|
||||
cp ../assets/rargray.png assets/
|
||||
cp ../assets/zip.png assets/
|
||||
cp ../assets/*.zim assets/
|
||||
cp ../assets/*.meta assets/
|
||||
cp ../assets/*.wav assets/
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.0 KiB |
+30
-22
@@ -23,9 +23,9 @@
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="5.6568542"
|
||||
inkscape:cx="272.05933"
|
||||
inkscape:cy="562.76861"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="361.75"
|
||||
inkscape:cy="499.625"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2071"
|
||||
inkscape:window-x="-9"
|
||||
@@ -608,7 +608,7 @@
|
||||
style="baseline-shift:baseline;display:inline;overflow:visible;vector-effect:none;fill:#ffffff;marker:none;enable-background:accumulate;stop-color:#000000"
|
||||
d="m 85.961667,41.562832 -1.122929,2.205034 v 8.189163 h 11.548648 v -8.343676 l -0.503845,-0.347782 h -4.517553 l -0.836125,-1.702739 z m 0.357601,0.583944 h 3.84731 l 0.834058,1.704805 h 4.701521 l 0.101286,0.06821 v 7.451224 H 85.424749 v -7.466727 z m 5.557283,1.927014 a 0.22366586,0.22366586 0 0 0 -0.128674,0.0124 0.22366586,0.22366586 0 0 0 -0.138493,0.206706 v 1.02526 l -2.105298,2.105815 h -1.025777 a 0.22366586,0.22366586 0 0 0 -0.15813,0.382922 l 0.959115,0.958598 -2.077909,2.078426 0.316259,0.316259 2.077909,-2.077909 0.961182,0.960665 a 0.22366586,0.22366586 0 0 0 0.380855,-0.15813 v -1.02526 l 2.105298,-2.105815 h 1.02526 a 0.22366586,0.22366586 0 0 0 0.158647,-0.382405 l -2.236556,-2.236556 a 0.22366586,0.22366586 0 0 0 -0.113688,-0.06098 z m 0.179834,0.76016 1.472778,1.472778 h -0.577742 a 0.22366586,0.22366586 0 0 0 -0.158647,0.0646 l -2.236039,2.236039 a 0.22366586,0.22366586 0 0 0 -0.06666,0.15813 v 0.578259 l -0.736389,-0.736389 -0.735872,-0.736389 h 0.577742 a 0.22366586,0.22366586 0 0 0 0.15813,-0.06408 l 2.236556,-2.236556 a 0.22366586,0.22366586 0 0 0 0.06615,-0.15813 z" /></g><g
|
||||
id="I_FLAG_ZZ"
|
||||
transform="matrix(0.02084888,0,0,0.02076933,79.611986,177.18799)"><rect
|
||||
transform="matrix(0.02084888,0,0,0.02076933,72.402091,176.92341)"><rect
|
||||
x="267.82452"
|
||||
y="105.90099"
|
||||
width="301.42874"
|
||||
@@ -621,7 +621,7 @@
|
||||
stroke-width="0.0767094"
|
||||
id="path2-8" /></g><g
|
||||
id="I_FLAG_HB"
|
||||
transform="matrix(0.01309261,0,0,0.01454735,85.195826,171.44998)"><rect
|
||||
transform="matrix(0.01309261,0,0,0.01454735,77.985931,171.1854)"><rect
|
||||
width="144"
|
||||
height="288"
|
||||
fill="#09f911"
|
||||
@@ -659,7 +659,7 @@
|
||||
d="m 441.82812,270.46875 q -1.28906,0.5625 -2.34375,1.05469 -1.03125,0.49218 -2.71875,1.03125 -1.42968,0.44531 -3.11718,0.75 -1.66407,0.32812 -3.67969,0.32812 -3.79688,0 -6.91406,-1.05469 -3.09375,-1.07812 -5.39063,-3.35156 -2.25,-2.22656 -3.51562,-5.64844 -1.26563,-3.44531 -1.26563,-7.99218 0,-4.3125 1.21875,-7.71094 1.21875,-3.39844 3.51563,-5.74219 2.22656,-2.27344 5.36718,-3.46875 3.16407,-1.19531 7.00782,-1.19531 2.8125,0 5.60156,0.67969 2.8125,0.67968 6.23437,2.39062 v 5.50781 h -0.35156 q -2.88281,-2.41406 -5.71875,-3.51562 -2.83594,-1.10156 -6.07031,-1.10156 -2.64844,0 -4.78125,0.86718 -2.10938,0.84375 -3.77344,2.64844 -1.61719,1.75781 -2.53125,4.45313 -0.89062,2.67187 -0.89062,6.1875 0,3.67968 0.98437,6.32812 1.00781,2.64844 2.57813,4.3125 1.64062,1.73438 3.82031,2.57813 2.20312,0.82031 4.64062,0.82031 3.35157,0 6.28125,-1.14844 2.92969,-1.14844 5.48438,-3.44531 h 0.32812 z m 29.22657,-14.92969 q 0,9.39844 -2.95313,13.80469 -2.92969,4.38281 -9.11719,4.38281 -6.28125,0 -9.1875,-4.45312 -2.88281,-4.45313 -2.88281,-13.6875 0,-9.30469 2.92969,-13.73438 2.92969,-4.45312 9.14062,-4.45312 6.28125,0 9.16407,4.52343 2.90625,4.5 2.90625,13.61719 z m -6.16407,10.64063 q 0.82032,-1.89844 1.10157,-4.45313 0.30468,-2.57812 0.30468,-6.1875 0,-3.5625 -0.30468,-6.1875 -0.28125,-2.625 -1.125,-4.45312 -0.82032,-1.80469 -2.25,-2.71875 -1.40625,-0.91407 -3.63282,-0.91407 -2.20312,0 -3.65625,0.91407 -1.42968,0.91406 -2.27343,2.76562 -0.79688,1.73438 -1.10157,4.52344 -0.28125,2.78906 -0.28125,6.11719 0,3.65625 0.25782,6.11718 0.25781,2.46094 1.10156,4.40625 0.77344,1.82813 2.17969,2.78907 1.42968,0.96093 3.77343,0.96093 2.20313,0 3.65625,-0.91406 1.45313,-0.91406 2.25,-2.76562 z"
|
||||
id="path8-2" /></g></g><g
|
||||
id="I_FLAG_KO"
|
||||
transform="matrix(0.04364203,0,0,0.04364203,88.338056,165.60729)"><path
|
||||
transform="matrix(0.04364203,0,0,0.04364203,81.128161,165.34271)"><path
|
||||
d="M -72,-48 V 48 H 72 v -96 z"
|
||||
fill="#ffffff"
|
||||
id="path9-4" /><g
|
||||
@@ -681,7 +681,7 @@
|
||||
fill="#0047a0"
|
||||
id="path13-7" /></g></g><g
|
||||
id="I_FLAG_AS"
|
||||
transform="matrix(0.00698273,0,0,0.00698273,85.195826,155.57498)"><path
|
||||
transform="matrix(0.00698273,0,0,0.00698273,77.985931,155.3104)"><path
|
||||
d="M 0,0 H 900 V 600 H 0"
|
||||
fill="#ee1c25"
|
||||
id="path14-1" /><g
|
||||
@@ -700,7 +700,7 @@
|
||||
d="m 310.58696,241.93248 -2.64767,57.00158 -31.36345,-47.67143 53.39425,20.13342 -55.03074,15.0947 z"
|
||||
id="path19-1" /></g></g></g><g
|
||||
id="I_FLAG_HK"
|
||||
transform="matrix(0.00698273,0,0,0.00698273,74.612496,179.38748)"
|
||||
transform="matrix(0.00698273,0,0,0.00698273,70.11458,179.1229)"
|
||||
fill="#ee1c25"><path
|
||||
d="M 0,0 H 900 V 600 H 0 Z"
|
||||
id="path20-2" /><g
|
||||
@@ -727,7 +727,7 @@
|
||||
d="m 337.53047,261.37524 2.91528,29.93052 15.2342,-25.92787 -27.56474,12.02164 29.36648,6.47644"
|
||||
id="path30-6" /></g><g
|
||||
id="I_FLAG_EU"
|
||||
transform="matrix(0.00775858,0,0,0.00775858,74.612496,171.44998)"><rect
|
||||
transform="matrix(0.00775858,0,0,0.00775858,70.11458,171.1854)"><rect
|
||||
width="810"
|
||||
height="540"
|
||||
fill="#003399"
|
||||
@@ -762,7 +762,7 @@
|
||||
d="M 2.9999993,4.1960485 3.2241204,4.8874547 H 3.9514153 L 3.3632805,5.3144567 3.5881341,6.0051305 2.9999993,5.5781285 2.4118645,6.0051305 2.636718,5.3144567 2.0485833,4.8874547 h 0.7265625 z"
|
||||
id="path42-3" /></g></g><g
|
||||
id="I_FLAG_US"
|
||||
transform="matrix(8.4810854e-4,0,0,0.00107427,74.612496,163.51248)"><path
|
||||
transform="matrix(8.4810854e-4,0,0,0.00107427,70.11458,163.2479)"><path
|
||||
d="M 0,0 H 7410 V 3900 H 0"
|
||||
fill="#bf0a30"
|
||||
id="path43-2" /><path
|
||||
@@ -876,7 +876,7 @@
|
||||
d="m 2717,1770 70.5342,217.082 -184.661,-134.164 h 228.2536 l -184.661,134.164 z"
|
||||
id="path95" /></g></g><g
|
||||
id="I_FLAG_JP"
|
||||
transform="matrix(0.00698273,0,0,0.00698273,74.612496,155.57498)"><rect
|
||||
transform="matrix(0.00698273,0,0,0.00698273,70.11458,155.3104)"><rect
|
||||
width="900"
|
||||
height="600"
|
||||
fill="#ffffff"
|
||||
@@ -1519,7 +1519,7 @@
|
||||
sodipodi:nodetypes="ccssssssccccccccccccccccccccccccccc" />
|
||||
</g><g
|
||||
id="I_DEVICE_ROTATION_LANDSCAPE_AUT"
|
||||
transform="rotate(-45,25.929944,64.565664)"><g
|
||||
transform="rotate(-45,24.804088,63.444509)"><g
|
||||
id="g6"
|
||||
transform="rotate(45,24.982115,122.88388)"><g
|
||||
id="g5"
|
||||
@@ -1568,16 +1568,24 @@
|
||||
id="path97" /></g><path
|
||||
id="rect8"
|
||||
style="fill:#ffffff;stroke-width:2.0069"
|
||||
d="m 153.47141,289.76429 h 2.55931 v 11.37002 h -2.55931 z" /></g><g
|
||||
id="g3"
|
||||
transform="matrix(0.63803159,0,0,0.63803159,35.189582,144.23096)"><path
|
||||
d="m 2.513663,19.0876 h 3.9114471 v -1 H 3.513663 V 4.5498022 h 1.2483801 v 2 H 14.762044 v -2 h 1.24838 v 3.699784 h 0.4 c 0.218953,0.0052 0.429987,0.08293 0.6,0.221 v -4.920784 h -2.24838 v -1 h -3 c 0,-2.66666568 -4.0000009,-2.66666568 -4.0000009,0 h -3 v 1 H 2.513663 Z M 5.7620431,3.5498022 h 2.9999998 v -1.385 c 0,-0.339265 0.274736,-0.6144483 0.614,-0.6149999 h 0.7710001 c 0.339655,0 0.615001,0.2753447 0.615001,0.6149999 v 1.385 h 3 v 2 H 5.7620431 Z M 9.9693869,16.227989 h 6.5118791 v 1 H 9.9693869 Z M 7.4251101,8.5498022 V 21.802503 H 18.481266 V 11.81287 l -3.6,-3.2630678 z M 17.481266,20.802503 H 8.4251099 V 9.5498022 h 5.3671711 v 3.3520528 h 3.688985 z m 0,-8.900648 H 14.792281 V 9.5498022 h -10e-4 l 2.69,2.3530678 z M 9.9693869,14.08328 h 6.5118791 v 1 H 9.9693869 Z m 0,4.237581 h 4.5118791 v 1 H 9.9693869 Z"
|
||||
id="I_FILE_PASTE"
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccscssccccccccccccccccccccccccccccccccccccccc" /><path
|
||||
fill="none"
|
||||
d="M 0,0 H 24 V 24 H 0 Z"
|
||||
id="path2-9" /></g></g><style
|
||||
d="m 153.47141,289.76429 h 2.55931 v 11.37002 h -2.55931 z" /></g><path
|
||||
d="m 37.354644,156.31591 h 2.495626 v -0.63803 h -1.857595 v -8.63754 h 0.796506 v 1.27606 h 6.380317 v -1.27606 h 0.796505 v 2.36058 h 0.255213 c 0.139699,0.003 0.274345,0.0529 0.382819,0.141 v -3.13961 h -1.434537 v -0.63804 h -1.914095 c 0,-1.70141 -2.552127,-1.70141 -2.552127,0 h -1.914095 v 0.63804 h -1.434537 z m 2.072569,-9.9136 h 1.914094 v -0.88368 c 0,-0.21646 0.175291,-0.39204 0.391752,-0.39239 h 0.491922 c 0.216711,0 0.39239,0.17568 0.39239,0.39239 v 0.88368 h 1.914095 v 1.27606 h -5.104253 z m 2.684418,8.08908 h 4.154785 v 0.63803 h -4.154785 z m -1.623329,-4.89893 v 8.45565 h 7.054177 v -6.37371 l -2.296914,-2.08194 z m 6.416145,7.81761 h -5.778113 v -7.17957 h 3.424424 v 2.13871 h 2.353689 z m 0,-5.67889 H 45.18879 v -1.50068 h -6.38e-4 l 1.716305,1.50133 z m -4.792816,1.39182 h 4.154785 v 0.63803 h -4.154785 z m 0,2.70371 h 2.878721 v 0.63803 h -2.878721 z"
|
||||
id="I_FILE_PASTE"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.638032"
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccscssccccccccccccccccccccccccccccccccccccccc" /><path
|
||||
fill="none"
|
||||
d="m 34.254138,143.06166 h 15.312758 v 15.31276 H 34.254138 Z"
|
||||
id="path2-9"
|
||||
style="stroke-width:0.638032" /><path
|
||||
id="I_ARCHIVE_ZIP"
|
||||
style="baseline-shift:baseline;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;stroke-width:0.936365;marker:none;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
|
||||
d="M 89.511836 153.65675 L 88.460221 155.72174 L 88.460221 163.39 L 98.880255 163.39 L 98.880255 155.57704 L 98.408449 155.25148 L 94.572508 155.25148 L 93.78961 153.65675 L 89.511836 153.65675 z M 89.846699 154.20348 L 93.449579 154.20348 L 94.23041 155.80029 L 98.237917 155.80029 L 98.333002 155.86437 L 98.333002 162.8412 L 89.009024 162.8412 L 89.009024 155.84938 L 89.846699 154.20348 z M 93.107482 156.75062 L 93.107482 157.22087 L 93.623212 157.22087 L 93.623212 156.75062 L 93.107482 156.75062 z M 95.535757 157.59708 C 95.373378 157.59708 95.222885 157.63181 95.084622 157.70095 C 94.947966 157.76847 94.823541 157.85288 94.711001 157.95416 L 94.711001 157.67201 L 94.257799 157.67201 L 94.257799 161.35912 L 94.711001 161.35912 L 94.711001 160.23051 C 94.818718 160.29483 94.923851 160.3426 95.026744 160.37313 C 95.129638 160.40367 95.247804 160.41861 95.381244 160.41861 C 95.709217 160.41861 95.980288 160.28597 96.194114 160.0207 C 96.409546 159.75382 96.51709 159.39645 96.517092 158.9479 C 96.517091 158.53633 96.430274 158.20835 96.256643 157.96398 C 96.084618 157.71961 95.844437 157.59708 95.535757 157.59708 z M 90.782559 157.67201 L 90.782559 158.04563 L 92.132864 158.04563 L 90.724682 160.03052 L 90.724682 160.3659 L 92.704405 160.3659 L 92.704405 159.98711 L 91.262633 159.98711 L 92.67805 157.99498 L 92.67805 157.67201 L 90.782559 157.67201 z M 93.138487 157.67201 L 93.138487 160.3659 L 93.592206 160.3659 L 93.592206 157.67201 L 93.138487 157.67201 z M 95.424652 158.02909 C 95.644909 158.02909 95.804073 158.11395 95.902143 158.28437 C 96.000213 158.45318 96.04942 158.69147 96.04942 158.99854 C 96.04942 159.32973 95.984308 159.581 95.854084 159.75302 C 95.723859 159.92504 95.541556 160.0114 95.30683 160.0114 C 95.197506 160.0114 95.100068 160.00081 95.014858 159.97988 C 94.931258 159.95896 94.829972 159.9194 94.711001 159.86154 L 94.711001 158.33502 C 94.818718 158.24498 94.932061 158.17166 95.051032 158.11539 C 95.171611 158.05752 95.296036 158.02909 95.424652 158.02909 z " /><path
|
||||
id="I_ARCHIVE_7Z"
|
||||
style="baseline-shift:baseline;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;stroke-width:0.936365;marker:none;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
|
||||
d="m 89.313398,164.24009 -1.051615,2.06499 v 7.66826 h 10.420034 v -7.81296 l -0.471805,-0.32556 h -3.835941 l -0.782898,-1.59473 z m 0.334863,0.54673 h 3.602881 l 0.780831,1.5968 h 4.007506 l 0.09508,0.0641 v 6.97684 h -9.323977 v -6.99182 z m 1.329118,2.9683 v 0.42219 h 1.857251 l -1.644861,3.1688 h 0.513664 l 1.552876,-3.05304 v -0.53795 z m 2.633431,0.8971 v 0.37362 h 1.350821 l -1.408699,1.98489 v 0.33538 h 1.980241 v -0.37879 h -1.442289 l 1.415417,-1.99212 v -0.32298 z" /><path
|
||||
id="I_ARCHIVE_RAR"
|
||||
style="baseline-shift:baseline;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;stroke-width:0.936365;marker:none;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
|
||||
d="M 89.379544 174.82341 L 88.327929 176.8884 L 88.327929 184.55667 L 98.747963 184.55667 L 98.747963 176.74371 L 98.276158 176.41815 L 94.440217 176.41815 L 93.657319 174.82341 L 89.379544 174.82341 z M 89.714407 175.37015 L 93.317288 175.37015 L 94.098119 176.96695 L 98.105625 176.96695 L 98.20071 177.03103 L 98.20071 184.00786 L 88.876733 184.00786 L 88.876733 177.01604 L 89.714407 175.37015 z M 93.285248 179.17043 C 93.132516 179.17043 92.978176 179.18491 92.822228 179.21384 C 92.66628 179.24277 92.546161 179.26929 92.46256 179.29342 L 92.46256 179.75386 L 92.489431 179.75386 C 92.63091 179.69436 92.772216 179.64952 92.913695 179.61898 C 93.055174 179.58685 93.178163 179.57093 93.282665 179.57093 C 93.371089 179.57093 93.456929 179.57718 93.54053 179.59005 C 93.624129 179.60131 93.69504 179.62539 93.75292 179.66239 C 93.810799 179.69775 93.855642 179.74839 93.887796 179.81432 C 93.919949 179.87863 93.936371 179.96401 93.936371 180.07012 L 93.936371 180.15694 C 93.69843 180.1698 93.476566 180.18955 93.270779 180.21688 C 93.064992 180.24261 92.886537 180.29038 92.735411 180.35951 C 92.564994 180.43668 92.440052 180.54083 92.361274 180.67267 C 92.282497 180.80289 92.243452 180.9616 92.243452 181.14809 C 92.243452 181.26866 92.265157 181.38344 92.308564 181.49277 C 92.351972 181.60049 92.409849 181.69115 92.482197 181.76511 C 92.557759 181.84067 92.645034 181.89952 92.744713 181.94132 C 92.844391 181.98312 92.950041 182.00385 93.060973 182.00385 C 93.196021 182.00385 93.300177 181.99279 93.374132 181.97026 C 93.449694 181.94773 93.52784 181.91543 93.608226 181.87363 C 93.666103 181.84472 93.725416 181.80614 93.78651 181.75787 C 93.849208 181.70804 93.899391 181.66945 93.936371 181.64212 L 93.936371 181.92944 L 94.38699 181.92944 L 94.38699 180.08666 C 94.38699 179.91784 94.362876 179.7751 94.314643 179.65774 C 94.266411 179.54037 94.193605 179.44437 94.095535 179.37042 C 93.994249 179.29485 93.879929 179.24277 93.75292 179.21384 C 93.625911 179.18491 93.470135 179.17043 93.285248 179.17043 z M 90.73605 179.23555 L 90.73605 181.92892 L 91.189253 181.92892 L 91.189253 180.01689 C 91.296969 179.91241 91.411289 179.83328 91.531867 179.78021 C 91.652446 179.72715 91.774 179.70063 91.896186 179.70063 C 91.949238 179.70063 91.994082 179.70247 92.031062 179.7058 C 92.069648 179.7074 92.105822 179.71319 92.139582 179.72285 L 92.16387 179.72285 L 92.16387 179.25053 C 92.13493 179.2452 92.108402 179.24153 92.084288 179.2402 C 92.061784 179.23686 92.027045 179.23555 91.980419 179.23555 C 91.864663 179.23555 91.745062 179.26595 91.621268 179.32701 C 91.499082 179.3865 91.354847 179.48922 91.189253 179.63552 L 91.189253 179.23555 L 90.73605 179.23555 z M 95.023643 179.23555 L 95.023643 181.92892 L 95.477362 181.92892 L 95.477362 180.01689 C 95.585079 179.91241 95.698882 179.83328 95.81946 179.78021 C 95.940038 179.72715 96.061593 179.70063 96.183779 179.70063 C 96.236831 179.70063 96.281675 179.70247 96.318655 179.7058 C 96.357242 179.7074 96.393415 179.71319 96.427175 179.72285 L 96.451463 179.72285 L 96.451463 179.25053 C 96.422523 179.2452 96.395995 179.24153 96.371881 179.2402 C 96.349376 179.23686 96.314638 179.23555 96.268012 179.23555 C 96.152256 179.23555 96.032654 179.26595 95.908861 179.32701 C 95.786675 179.3865 95.642957 179.48922 95.477362 179.63552 L 95.477362 179.23555 L 95.023643 179.23555 z M 93.936371 180.51867 L 93.936371 181.26591 C 93.835085 181.35591 93.726565 181.43262 93.61081 181.49536 C 93.495055 181.55642 93.365289 181.58682 93.222203 181.58682 C 93.055001 181.58682 92.928165 181.54726 92.841348 181.46848 C 92.754532 181.3897 92.711123 181.27349 92.711123 181.11915 C 92.711123 180.9825 92.750685 180.87639 92.829462 180.80082 C 92.90824 180.72368 93.007573 180.66626 93.128152 180.62926 C 93.229438 180.59872 93.362075 180.57556 93.526061 180.5595 C 93.691655 180.54183 93.828655 180.52834 93.936371 180.51867 z " /></g><style
|
||||
type="text/css"
|
||||
id="style1">
|
||||
.st0{fill:#000000;}
|
||||
|
||||
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 164 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB |
Reference in new issue
Block a user