📄 popupmenuchromium.cpp
字号:
gc->fillRect(rowRect, Color::white); gc->fillRect(rowRect, backColor); if (m_popupClient->itemIsSeparator(rowIndex)) { IntRect separatorRect( rowRect.x() + separatorPadding, rowRect.y() + (rowRect.height() - separatorHeight) / 2, rowRect.width() - 2 * separatorPadding, separatorHeight); gc->fillRect(separatorRect, textColor); return; } gc->setFillColor(textColor); // Bunch of shit to deal with RTL text... String itemText = m_popupClient->itemText(rowIndex); unsigned length = itemText.length(); const UChar* str = itemText.characters(); TextRun textRun(str, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft); // FIXME: http://b/1210481 We should get the padding of individual option // elements. This probably implies changes to PopupMenuClient. // Draw the item text if (style.isVisible()) { Font itemFont = getRowFont(rowIndex); int textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft()); int textY = rowRect.y() + itemFont.ascent() + (rowRect.height() - itemFont.height()) / 2; gc->drawBidiText(itemFont, textRun, IntPoint(textX, textY)); }}Font PopupListBox::getRowFont(int rowIndex){ Font itemFont = m_popupClient->itemStyle(rowIndex).font(); if (m_popupClient->itemIsLabel(rowIndex)) { // Bold-ify labels (ie, an <optgroup> heading). FontDescription d = itemFont.fontDescription(); d.setWeight(FontWeightBold); Font font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); font.update(0); return font; } return itemFont;}void PopupListBox::abandon(){ RefPtr<PopupListBox> keepAlive(this); m_selectedIndex = m_originalIndex; m_popupClient->hidePopup(); if (m_willAcceptOnAbandon) m_popupClient->valueChanged(m_selectedIndex);}int PopupListBox::pointToRowIndex(const IntPoint& point){ int y = scrollY() + point.y(); // FIXME: binary search if perf matters. for (int i = 0; i < numItems(); ++i) { if (y < m_items[i]->y) return i-1; } // Last item? if (y < contentsHeight()) return m_items.size()-1; return -1;}void PopupListBox::acceptIndex(int index){ ASSERT(index >= -1 && index < numItems()); if (index == -1 && m_popupClient) { // Enter pressed with no selection, just close the popup. m_popupClient->hidePopup(); return; } if (isSelectableItem(index)) { RefPtr<PopupListBox> keepAlive(this); // Hide ourselves first since valueChanged may have numerous side-effects. m_popupClient->hidePopup(); // Tell the <select> PopupMenuClient what index was selected. m_popupClient->valueChanged(index); }}void PopupListBox::selectIndex(int index){ ASSERT(index >= 0 && index < numItems()); if (index != m_selectedIndex && isSelectableItem(index)) { invalidateRow(m_selectedIndex); m_selectedIndex = index; invalidateRow(m_selectedIndex); scrollToRevealSelection(); }}void PopupListBox::setOriginalIndex(int index){ m_originalIndex = m_selectedIndex = index;}int PopupListBox::getRowHeight(int index){ if (index < 0) return 0; return m_popupClient->itemStyle(index).font().height();}IntRect PopupListBox::getRowBounds(int index){ if (index < 0) return IntRect(0, 0, visibleWidth(), getRowHeight(index)); return IntRect(0, m_items[index]->y, visibleWidth(), getRowHeight(index));}void PopupListBox::invalidateRow(int index){ if (index < 0) return; // Invalidate in the window contents, as FramelessScrollView::invalidateRect // paints in the window coordinates. invalidateRect(contentsToWindow(getRowBounds(index)));}void PopupListBox::scrollToRevealRow(int index){ if (index < 0) return; IntRect rowRect = getRowBounds(index); if (rowRect.y() < scrollY()) { // Row is above current scroll position, scroll up. ScrollView::setScrollPosition(IntPoint(0, rowRect.y())); } else if (rowRect.bottom() > scrollY() + visibleHeight()) { // Row is below current scroll position, scroll down. ScrollView::setScrollPosition(IntPoint(0, rowRect.bottom() - visibleHeight())); }}bool PopupListBox::isSelectableItem(int index){ return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(index);}void PopupListBox::clearSelection(){ if (m_selectedIndex != -1) { invalidateRow(m_selectedIndex); m_selectedIndex = -1; }}void PopupListBox::selectNextRow(){ if (!m_settings.loopSelectionNavigation || m_selectedIndex != numItems() - 1) { adjustSelectedIndex(1); return; } // We are moving past the last item, no row should be selected. clearSelection();}void PopupListBox::selectPreviousRow(){ if (!m_settings.loopSelectionNavigation || m_selectedIndex > 0) { adjustSelectedIndex(-1); return; } if (m_selectedIndex == 0) { // We are moving past the first item, clear the selection. clearSelection(); return; } // No row are selected, jump to the last item. selectIndex(numItems() - 1); scrollToRevealSelection();}void PopupListBox::adjustSelectedIndex(int delta){ int targetIndex = m_selectedIndex + delta; targetIndex = min(max(targetIndex, 0), numItems() - 1); if (!isSelectableItem(targetIndex)) { // We didn't land on an option. Try to find one. // We try to select the closest index to target, prioritizing any in // the range [current, target]. int dir = delta > 0 ? 1 : -1; int testIndex = m_selectedIndex; int bestIndex = m_selectedIndex; bool passedTarget = false; while (testIndex >= 0 && testIndex < numItems()) { if (isSelectableItem(testIndex)) bestIndex = testIndex; if (testIndex == targetIndex) passedTarget = true; if (passedTarget && bestIndex != m_selectedIndex) break; testIndex += dir; } // Pick the best index, which may mean we don't change. targetIndex = bestIndex; } // Select the new index, and ensure its visible. We do this regardless of // whether the selection changed to ensure keyboard events always bring the // selection into view. selectIndex(targetIndex); scrollToRevealSelection();}void PopupListBox::updateFromElement(){ // It happens when pressing a key to jump to an item, then use tab or // mouse to get away from the select box. In that case, updateFromElement // is called before abandon, which causes discarding of the select result. if (m_willAcceptOnAbandon) { m_popupClient->valueChanged(m_selectedIndex); m_willAcceptOnAbandon = false; } clear(); int size = m_popupClient->listSize(); for (int i = 0; i < size; ++i) { ListItemType type; if (m_popupClient->itemIsSeparator(i)) type = PopupListBox::TypeSeparator; else if (m_popupClient->itemIsLabel(i)) type = PopupListBox::TypeGroup; else type = PopupListBox::TypeOption; m_items.append(new ListItem(m_popupClient->itemText(i), type)); } m_selectedIndex = m_popupClient->selectedIndex(); setOriginalIndex(m_selectedIndex); layout();}void PopupListBox::layout(){ // Size our child items. int baseWidth = 0; int paddingWidth = 0; int y = 0; for (int i = 0; i < numItems(); ++i) { Font itemFont = getRowFont(i); // Place the item vertically. m_items[i]->y = y; y += itemFont.height(); // Ensure the popup is wide enough to fit this item. String text = m_popupClient->itemText(i); if (!text.isEmpty()) { int width = itemFont.width(TextRun(text)); baseWidth = max(baseWidth, width); } // FIXME: http://b/1210481 We should get the padding of individual option elements. paddingWidth = max(paddingWidth, m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRight()); } int windowHeight = 0; m_visibleRows = min(numItems(), kMaxVisibleRows); for (int i = 0; i < m_visibleRows; ++i) { int rowHeight = getRowHeight(i); if (windowHeight + rowHeight > kMaxHeight) { m_visibleRows = i; break; } windowHeight += rowHeight; } // Set our widget and scrollable contents sizes. int scrollbarWidth = 0; if (m_visibleRows < numItems()) scrollbarWidth = ScrollbarTheme::nativeTheme()->scrollbarThickness(); int windowWidth = baseWidth + scrollbarWidth + paddingWidth; int contentWidth = baseWidth; if (windowWidth < m_baseWidth) { windowWidth = m_baseWidth; contentWidth = m_baseWidth - scrollbarWidth - paddingWidth; } else { m_baseWidth = baseWidth; } resize(windowWidth, windowHeight); setContentsSize(IntSize(contentWidth, getRowBounds(numItems() - 1).bottom())); if (hostWindow()) scrollToRevealSelection(); invalidate();}void PopupListBox::clear(){ for (Vector<ListItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) delete *it; m_items.clear();}bool PopupListBox::isPointInBounds(const IntPoint& point){ return numItems() != 0 && IntRect(0, 0, width(), height()).contains(point);}///////////////////////////////////////////////////////////////////////////////// PopupMenu implementation// // Note: you cannot add methods to this class, since it is defined above the // portability layer. To access methods and properties on the// popup widgets, use |popupWindow| above. PopupMenu::PopupMenu(PopupMenuClient* client) : m_popupClient(client){}PopupMenu::~PopupMenu(){ hide();}void PopupMenu::show(const IntRect& r, FrameView* v, int index) { if (!p.popup) p.popup = PopupContainer::create(client(), dropDownSettings); p.popup->show(r, v, index);}void PopupMenu::hide(){ if (p.popup) p.popup->hidePopup();}void PopupMenu::updateFromElement(){ p.popup->listBox()->updateFromElement();}bool PopupMenu::itemWritingDirectionIsNatural() { return false; }} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -