void FileSelector::RefreshFiles() { FileSystem* fileSystem = GetSubsystem<FileSystem>(); ignoreEvents_ = true; fileList_->RemoveAllItems(); fileEntries_.Clear(); Vector<String> directories; Vector<String> files; fileSystem->ScanDir(directories, path_, "*", SCAN_DIRS, false); fileSystem->ScanDir(files, path_, GetFilter(), SCAN_FILES, false); fileEntries_.Reserve(directories.Size() + files.Size()); for (unsigned i = 0; i < directories.Size(); ++i) { FileSelectorEntry newEntry; newEntry.name_ = directories[i]; newEntry.directory_ = true; fileEntries_.Push(newEntry); } for (unsigned i = 0; i < files.Size(); ++i) { FileSelectorEntry newEntry; newEntry.name_ = files[i]; newEntry.directory_ = false; fileEntries_.Push(newEntry); } // Sort and add to the list view // While items are being added, disable layout update for performance optimization Sort(fileEntries_.Begin(), fileEntries_.End(), CompareEntries); UIElement* listContent = fileList_->GetContentElement(); listContent->DisableLayoutUpdate(); for (unsigned i = 0; i < fileEntries_.Size(); ++i) { String displayName; if (fileEntries_[i].directory_) displayName = "<DIR> " + fileEntries_[i].name_; else displayName = fileEntries_[i].name_; Text* entryText = new Text(context_); fileList_->AddItem(entryText); entryText->SetText(displayName); entryText->SetStyle("FileSelectorListText"); } listContent->EnableLayoutUpdate(); listContent->UpdateLayout(); ignoreEvents_ = false; // Clear filename from the previous dir so that there is no confusion SetFileName(String::EMPTY); lastUsedFilter_ = GetFilter(); }
void DropDownList::OnShowPopup() { // Resize the popup to match the size of the list content, and optionally match the button width UIElement* content = listView_->GetContentElement(); content->UpdateLayout(); const IntVector2& contentSize = content->GetSize(); const IntRect& border = popup_->GetLayoutBorder(); popup_->SetSize(resizePopup_ ? GetWidth() : contentSize.x_ + border.left_ + border.right_, contentSize.y_ + border.top_ + border.bottom_); // Check if popup fits below the button. If not, show above instead bool showAbove = false; UIElement* root = GetRoot(); if (root) { const IntVector2& screenPos = GetScreenPosition(); if (screenPos.y_ + GetHeight() + popup_->GetHeight() > root->GetHeight() && screenPos.y_ - popup_->GetHeight() >= 0) showAbove = true; } SetPopupOffset(0, showAbove ? -popup_->GetHeight() : GetHeight()); }
void Text::UpdateText(bool onResize) { rowWidths_.clear(); printText_.clear(); if (font_) { FontFace* face = font_->GetFace(fontSize_); if (!face) return; rowHeight_ = face->GetRowHeight(); int width = 0; int height = 0; int rowWidth = 0; auto rowHeight = RoundToInt(rowSpacing_ * rowHeight_); // First see if the text must be split up if (!wordWrap_) { printText_ = unicodeText_; printToText_.resize(printText_.size()); for (unsigned i = 0; i < printText_.size(); ++i) printToText_[i] = i; } else { int maxWidth = GetWidth(); unsigned nextBreak = 0; unsigned lineStart = 0; printToText_.clear(); for (unsigned i = 0; i < unicodeText_.size(); ++i) { unsigned j; unsigned c = unicodeText_[i]; if (c != '\n') { bool ok = true; if (nextBreak <= i) { int futureRowWidth = rowWidth; for (j = i; j < unicodeText_.size(); ++j) { unsigned d = unicodeText_[j]; if (d == ' ' || d == '\n') { nextBreak = j; break; } const FontGlyph* glyph = face->GetGlyph(d); if (glyph) { futureRowWidth += glyph->advanceX_; if (j < unicodeText_.size() - 1) futureRowWidth += face->GetKerning(d, unicodeText_[j + 1]); } if (d == '-' && futureRowWidth <= maxWidth) { nextBreak = j + 1; break; } if (futureRowWidth > maxWidth) { ok = false; break; } } } if (!ok) { // If did not find any breaks on the line, copy until j, or at least 1 char, to prevent infinite loop if (nextBreak == lineStart) { while (i < j) { printText_.push_back(unicodeText_[i]); printToText_.push_back(i); ++i; } } // Eliminate spaces that have been copied before the forced break while (printText_.size() && printText_.back() == ' ') { printText_.pop_back(); printToText_.pop_back(); } printText_.push_back('\n'); printToText_.push_back(Min(i, unicodeText_.size() - 1)); rowWidth = 0; nextBreak = lineStart = i; } if (i < unicodeText_.size()) { // When copying a space, position is allowed to be over row width c = unicodeText_[i]; const FontGlyph* glyph = face->GetGlyph(c); if (glyph) { rowWidth += glyph->advanceX_; if (i < unicodeText_.size() - 1) rowWidth += face->GetKerning(c, unicodeText_[i + 1]); } if (rowWidth <= maxWidth) { printText_.push_back(c); printToText_.push_back(i); } } } else { printText_.push_back('\n'); printToText_.push_back(Min(i, unicodeText_.size() - 1)); rowWidth = 0; nextBreak = lineStart = i; } } } rowWidth = 0; for (unsigned i = 0; i < printText_.size(); ++i) { unsigned c = printText_[i]; if (c != '\n') { const FontGlyph* glyph = face->GetGlyph(c); if (glyph) { rowWidth += glyph->advanceX_; if (i < printText_.size() - 1) rowWidth += face->GetKerning(c, printText_[i + 1]); } } else { width = Max(width, rowWidth); height += rowHeight; rowWidths_.push_back(rowWidth); rowWidth = 0; } } if (rowWidth) { width = Max(width, rowWidth); height += rowHeight; rowWidths_.push_back(rowWidth); } // Set at least one row height even if text is empty if (!height) height = rowHeight; // Set minimum and current size according to the text size, but respect fixed width if set if (!IsFixedWidth()) { if (wordWrap_) SetMinWidth(0); else { SetMinWidth(width); SetWidth(width); } } SetFixedHeight(height); charLocationsDirty_ = true; } else { // No font, nothing to render pageGlyphLocations_.clear(); } // If wordwrap is on, parent may need layout update to correct for overshoot in size. However, do not do this when the // update is a response to resize, as that could cause infinite recursion if (wordWrap_ && !onResize) { UIElement* parent = GetParent(); if (parent && parent->GetLayoutMode() != LM_FREE) parent->UpdateLayout(); } }