Skip to content

Commit

Permalink
Merge pull request #1189 from kiwix/Issue#413-search-UI-improvement
Browse files Browse the repository at this point in the history
Implement Fine-Tuned Zim Search
  • Loading branch information
kelson42 authored Oct 28, 2024
2 parents adfd924 + c3f4a1e commit 0585c34
Show file tree
Hide file tree
Showing 16 changed files with 298 additions and 26 deletions.
3 changes: 3 additions & 0 deletions kiwix-desktop.pro
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ SOURCES += \
src/rownode.cpp \
src/suggestionlistworker.cpp \
src/suggestionlistmodel.cpp \
src/suggestionlistdelegate.cpp \
src/thumbnaildownloader.cpp \
src/translation.cpp \
src/main.cpp \
Expand Down Expand Up @@ -111,6 +112,7 @@ HEADERS += \
src/rownode.h \
src/suggestionlistworker.h \
src/suggestionlistmodel.h \
src/suggestionlistdelegate.h \
src/thumbnaildownloader.h \
src/translation.h \
src/mainwindow.h \
Expand Down Expand Up @@ -140,6 +142,7 @@ HEADERS += \
src/menuproxystyle.h \
src/zimview.h \
src/portutils.h \
src/css_constants.h \

FORMS += \
src/choiceitem.ui \
Expand Down
3 changes: 2 additions & 1 deletion resources/css/_contentManager.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ QTreeView::item:has-children {
border-bottom: 1px solid #cccccc;
}


QTreeView {
font-family: 'Selawik';
padding: 4px;
padding: 4px; /* XXX: duplicated in css_constants.h */
border: none;
selection-color: black;
qproperty-iconSize: 30px;
Expand Down
30 changes: 29 additions & 1 deletion resources/css/popup.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
QWidget {
QTreeView {
background-color: white;
border: none;
outline: none;
}

QTreeView::item {
border: 1px solid transparent;
}

QTreeView::item:selected {
border: 1px solid #3366CC;
background-color: #D9E9FF;
color: black;
}

QHeaderView {
background-color: white;
}

QHeaderView::section {
border: none;
color: #3b3b3b;
background-color: white;

margin-top: 5px; /* XXX: duplicated in css_constants.h */
padding: 5px 10px; /* XXX: duplicated in css_constants.h */

font-size: 16px;
line-height: 24px; /* XXX: duplicated in css_constants.h */
font-weight: 400;
}

QScrollBar {
Expand Down
18 changes: 6 additions & 12 deletions resources/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ QToolButton {

SearchBar {
background-color: white;
margin: 2px 5px;
border: 1px solid #ccc;
margin: 2px; /* XXX: duplicated in css_constants.h */
border: 1px solid #ccc; /* XXX: duplicated in css_constants.h */
border-radius: 3px;

max-height: 40px;
Expand All @@ -43,7 +43,7 @@ SearchBar > QLabel#searchIcon {
padding: 0;
border: none;
background-color: none;
margin: 0px 4px 0px 9px;
margin: 0px 6px;

max-height: 38px;
max-width: 38px;
Expand All @@ -68,11 +68,6 @@ SearchBar > QToolButton {
max-width: 38px;
}

SearchBar > BookmarkButton {
margin-right: 3px;
margin-left: 3px;
}

SearchBar > QToolButton:pressed,
SearchBar > QToolButton:hover {
border: 1px solid #3366CC;
Expand Down Expand Up @@ -103,7 +98,7 @@ TopWidget QToolButton::menu-indicator {
}

TopWidget QToolButton#backButton {
margin-left: 6px; /* see also: void WebViewBackMenu::showEvent(QShowEvent *) { geo.setX(geo.x() + 6); } */
margin-left: 6px; /* XXX: duplicated in css_constants.h */
}

TopWidget QToolButton#fullScreenButton {
Expand Down Expand Up @@ -178,11 +173,10 @@ QTabWidget::pane {
border-top: 1px solid #ccc;
}

/* paintEvent of src/tabbar.cpp references the value of border and padding */
QTabBar::tab {
border: 1px solid #ccc;
border: 1px solid #ccc; /* XXX: duplicated in css_constants.h */
border-radius: 0;
padding: 4px;
padding: 4px; /* XXX: duplicated in css_constants.h */
padding-top: 6px;
}

Expand Down
6 changes: 3 additions & 3 deletions src/contentmanagerdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "rownode.h"
#include "descriptionnode.h"
#include "portutils.h"
#include "css_constants.h"

ContentManagerDelegate::ContentManagerDelegate(QObject *parent)
: QStyledItemDelegate(parent), baseButton(new QPushButton)
Expand Down Expand Up @@ -284,9 +285,8 @@ QSize ContentManagerDelegate::sizeHint(const QStyleOptionViewItem &option, const
const auto treeView = KiwixApp::instance()->getContentManager()->getView()->getView();

const int width = treeView->header()->length() - 2*treeView->indentation();
// XXX: see QTreeView::padding in resources/css/_contentManager.css
const int verticalPadding = 4;
const int horizontalPadding = 4;
const int verticalPadding = CSS::ContentManagerCSS::QTreeView::padding;
const int horizontalPadding = CSS::ContentManagerCSS::QTreeView::padding;
QRect descRect(0, 0, width - 2 * horizontalPadding, 0);

/* Based on the rectangle and text, find the best fitting size. */
Expand Down
60 changes: 60 additions & 0 deletions src/css_constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#ifndef CSS_CONSTANTS_H
#define CSS_CONSTANTS_H

/**
* @brief The need for this file is due to the lack of support to retrieve CSS
* values of Qt Widgets. Such deficiency means every code that depend on a CSS
* values need to be updated on change to that value. This file makes it so that
* a dependent CSS value only need to be updated here instead of its every use.
*
* - The CSS values in this file should create appropriate namespaces similar to
* a CSS hierarchy.
* - The classes are defined in resources/style.css unless specified.
* - Naming convention should follow Javascript's style naming.
* - Comments should be added to the duplicated css properties in css files.
*/
namespace CSS
{

namespace QTabBar {
namespace tab {
const int padding = 4;
const int border = 1;
}
}

namespace SearchBar{
const int margin = 2;
const int border = 1;
}

namespace TopWidget {
namespace QToolButton {
namespace backButton {
const int marginLeft = 6;
}
}
}

/* In _contentManager.css */
namespace ContentManagerCSS {
namespace QTreeView {
const int padding = 4;
}
}

/* In popup.css */
namespace PopupCSS {
namespace QHeaderView {
namespace section {
const int marginTop = 5;
const int lineHeight = 24;
const int paddingVertical = 5;
const int paddingLeft = 10;
}
}
}

}

#endif // CSS_CONSTANTS_H
2 changes: 1 addition & 1 deletion src/kiwixapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ KiwixApp::~KiwixApp()
void KiwixApp::newTab()
{
getTabWidget()->createNewTab(true, false);
auto& searchBarLineEdit = mp_mainWindow->getTopWidget()->getSearchBar().getLineEdit();
auto& searchBarLineEdit = getSearchBar().getLineEdit();
searchBarLineEdit.setFocus(Qt::MouseFocusReason);
searchBarLineEdit.clear();
searchBarLineEdit.clearSuggestions();
Expand Down
1 change: 1 addition & 0 deletions src/kiwixapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class KiwixApp : public QtSingleApplication
MainWindow* getMainWindow() { return mp_mainWindow; }
ContentManager* getContentManager() { return mp_manager; }
TabBar* getTabWidget() { return getMainWindow()->getTabBar(); }
SearchBar& getSearchBar() { return getMainWindow()->getTopWidget()->getSearchBar(); }
QAction* getAction(Actions action);
QString getLibraryDirectory() { return m_libraryDirectory; };
kiwix::Server* getLocalServer() { return &m_server; }
Expand Down
64 changes: 63 additions & 1 deletion src/searchbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
#include <QCompleter>
#include <QFocusEvent>
#include <QScrollBar>
#include <QStyledItemDelegate>

#include "kiwixapp.h"
#include "suggestionlistworker.h"
#include "css_constants.h"
#include "suggestionlistdelegate.h"

namespace HeaderSectionCSS = CSS::PopupCSS::QHeaderView::section;

BookmarkButton::BookmarkButton(QWidget *parent) :
QToolButton(parent)
Expand Down Expand Up @@ -76,10 +81,30 @@ SearchBarLineEdit::SearchBarLineEdit(QWidget *parent) :
/* QCompleter's uses default list views, which do not have headers. */
m_completer.setPopup(m_suggestionView);

/* The Delegate was overwritten by setPopup(), which is not style-aware */
m_suggestionView->setItemDelegate(new SuggestionListDelegate(this));
m_suggestionView->header()->setStretchLastSection(true);
m_suggestionView->setRootIsDecorated(false);
m_suggestionView->setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/popup.css"));

const int contentHeight = HeaderSectionCSS::lineHeight;
m_suggestionView->setIconSize(QSize(contentHeight, contentHeight));

/* The suggestionView sizing unfortunately is not aware of headers. We
have to do this manually. We also sized header the same as items.
*/
connect(&m_suggestionModel, &QAbstractListModel::modelReset, [=](){
/* +1 for header. */
const int maxItem = m_completer.maxVisibleItems();
const int count = std::min(m_suggestionModel.rowCount(), maxItem) + 1;

const int itemHeight = m_suggestionView->sizeHintForRow(0);

/* Extra space styling above header and below last suggestion item. */
const int extraMargin = 2 * HeaderSectionCSS::marginTop;
m_suggestionView->setFixedHeight(itemHeight * count + extraMargin);
});

connect(m_suggestionView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &SearchBarLineEdit::onScroll);

Expand Down Expand Up @@ -285,7 +310,7 @@ void SearchBarLineEdit::onInitialSuggestions(int)
if (m_returnPressed) {
openCompletion(getDefaulSuggestionIndex());
} else {
m_completer.complete();
m_completer.complete(getCompleterRect());

/* Make row 0 appear but do not highlight it */
const auto completerFirstIdx = m_suggestionView->model()->index(0, 0);
Expand Down Expand Up @@ -339,6 +364,43 @@ QModelIndex SearchBarLineEdit::getDefaulSuggestionIndex() const
return QModelIndex();
}

/* Line edit does not span the entire searchBar. Completer is displayed
based on line edit, and thus shifting and resizing is needed.
*/
QRect SearchBarLineEdit::getCompleterRect() const
{
auto& searchBar = KiwixApp::instance()->getSearchBar();
const auto& searchGeo = searchBar.geometry();
const auto& searchLineEditGeo = searchBar.getLineEdit().geometry();

const int margin = CSS::SearchBar::margin;
const int border = CSS::SearchBar::border;
const int spaceAround = margin + border;

/* Border and margin are not accounted in height and width. */
const int top = searchGeo.height() - 2 * spaceAround;
const int width = searchGeo.width() - 2 * spaceAround;

/* Shift completer to one of the two laterals of search bar, where which
one it shifted to dependes on whether the line edit is flipped.
*/
int left = -searchLineEditGeo.left();

/* When not flipped, left() is relative to within the search bar border,
thus, we shift by spaceAround to match the side of search bar.
When flipped, the completer starts at the right end of the search bar
We shift it by width to make the completer start at left lateral of
search bar. Since in a flipped state, left() also considered the opposite
side's border, which means we need to shift by a border width in
addition to spaceAround.
*/
left += isRightToLeft() ? -width + spaceAround + border : spaceAround;

/* Can't set height to 0. Will cause rectangle to be ignored. */
return QRect(QPoint(left, top), QSize(width, 1));
}

SearchBar::SearchBar(QWidget *parent) :
QToolBar(parent),
m_searchBarLineEdit(this),
Expand Down
1 change: 1 addition & 0 deletions src/searchbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private slots:
void fetchSuggestions(NewSuggestionHandlerFuncPtr callback);

QModelIndex getDefaulSuggestionIndex() const;
QRect getCompleterRect() const;
};


Expand Down
Loading

0 comments on commit 0585c34

Please sign in to comment.