View Issue Details

IDProjectCategoryView StatusLast Update
0017162ScribusStylespublic2024-06-21 16:02
Reporterale Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status newResolutionopen 
Product Version1.7.0.svn 
Summary0017162: [PATCH] apply style "shortcuts" based on the "action search" tool
Descriptionfinally, i have recreated the applyStyle plugin as a "clone" of the actionSearch tool.

there are a few question open:

- where to attach it in the menus (i've picked Item > Text features).
  even if the user is not supposed to use the menus to start it, for discoverability purposes, it's worth to have it somewhere in the navigation.
- which shortcut to use to start it: i'm using ctrl-shift-space.
  ctrl-space would probably be better (we would then use ctrl-shift-space to the special space that is inserted with ctrl-space)
  anyway, it should be something that is very simple to reach.
- if and how extend the tool to also support other types of formatting.

a patch will follow very soon.
TagsNo tags attached.
PatchYes

Relationships

related to 0010289 new [patch] make shortcuts for styles working 

Activities

ale

2024-02-16 19:55

manager   ~0050995

here a small visual preview.
apply-style-does-work.gif (84,770 bytes)   
apply-style-does-work.gif (84,770 bytes)   

ale

2024-02-16 20:58

manager   ~0050996

here is the patch!
style-search.diff (25,095 bytes)   
diff --git a/Scribus.pro b/Scribus.pro
index eacc9380d..5ff744d01 100644
--- a/Scribus.pro
+++ b/Scribus.pro
@@ -232,6 +232,7 @@ HEADERS += scribus/actionmanager.h \
            scribus/style.h \
            scribus/styleitem.h \
            scribus/styleoptions.h \
+           scribus/stylesearch.h \
            scribus/tableborder.h \
            scribus/tablecell.h \
            scribus/tablehandle.h \
@@ -647,6 +648,7 @@ HEADERS += scribus/actionmanager.h \
            scribus/ui/storyeditor.h \
            scribus/ui/stylecombos.h \
            scribus/ui/stylemanager.h \
+           scribus/ui/stylesearchdialog.h \
            scribus/ui/styleselect.h \
            scribus/ui/styleview.h \
            scribus/ui/swatchcombo.h \
@@ -1168,6 +1170,7 @@ FORMS += scribus/ui/aboutplugins.ui \
          scribus/ui/spiralvectorbase.ui \
          scribus/ui/spiralwidgetbase.ui \
          scribus/ui/stylemanager.ui \
+         scribus/ui/stylesearchdialog.ui \
          scribus/ui/tablecolumnwidthsdialog.ui \
          scribus/ui/tablerowheightsdialog.ui \
          scribus/ui/tabpdfoptions.ui \
@@ -1400,6 +1403,7 @@ SOURCES += scribus/actionmanager.cpp \
            scribus/serializer.cpp \
            scribus/storyloader.cpp \
            scribus/styleitem.cpp \
+           scribus/stylesearch.cpp \
            scribus/tableborder.cpp \
            scribus/tablecell.cpp \
            scribus/tableutils.cpp \
@@ -1796,6 +1800,7 @@ SOURCES += scribus/actionmanager.cpp \
            scribus/ui/stylecombos.cpp \
            scribus/ui/stylemanager.cpp \
            scribus/ui/styleselect.cpp \
+           scribus/ui/stylesearchdialog.cpp \
            scribus/ui/styleview.cpp \
            scribus/ui/swatchcombo.cpp \
            scribus/ui/symbolpalette.cpp \
diff --git a/scribus/CMakeLists_Sources.txt b/scribus/CMakeLists_Sources.txt
index 66101c2e1..6ac4834c8 100644
--- a/scribus/CMakeLists_Sources.txt
+++ b/scribus/CMakeLists_Sources.txt
@@ -211,6 +211,7 @@ set(SCRIBUS_SOURCES
 	serializer.cpp
 	storyloader.cpp
 	styleitem.cpp
+	stylesearch.cpp
 	tableborder.cpp
 	tablecell.cpp
 	tableutils.cpp
@@ -513,6 +514,7 @@ set(SCRIBUS_SOURCES
 	ui/storyeditor.cpp
 	ui/stylecombos.cpp
 	ui/stylemanager.cpp
+	ui/stylesearchdialog.cpp
 	ui/styleselect.cpp
 	ui/styleview.cpp
 	ui/swatchcombo.cpp
diff --git a/scribus/actionmanager.cpp b/scribus/actionmanager.cpp
index 7bbd81527..44acfcecc 100644
--- a/scribus/actionmanager.cpp
+++ b/scribus/actionmanager.cpp
@@ -305,6 +305,9 @@ void ActionManager::initStyleMenuActions()
 		connect( (*scrActions)[fontSizeName], SIGNAL(triggeredData(int)), mainWindow, SLOT(setItemFontSize(int)));
 	}
 
+	name = "itemStyleSearch";
+	scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow));
+
 	//Alignment actions
 	name = "alignLeft";
 	scrActions->insert(name, new ScrAction(ScrAction::DataInt, QString(), QString(), "", defaultKey(name), mainWindow, 0));
@@ -323,6 +326,8 @@ void ActionManager::initStyleMenuActions()
 //	(*scrActions)["alignBlock"]->setToggleAction(true);
 //	(*scrActions)["alignForced"]->setToggleAction(true);
 
+	connect( (*scrActions)["itemStyleSearch"], SIGNAL(triggered()), mainWindow, SLOT(slotItemStyleSearch()) );
+
 	connect( (*scrActions)["alignLeft"], SIGNAL(triggeredData(int)), mainWindow, SLOT(setNewAlignment(int)));
 	connect( (*scrActions)["alignCenter"], SIGNAL(triggeredData(int)), mainWindow, SLOT(setNewAlignment(int)));
 	connect( (*scrActions)["alignRight"], SIGNAL(triggeredData(int)), mainWindow, SLOT(setNewAlignment(int)));
@@ -1549,6 +1554,9 @@ void ActionManager::languageChange()
 		(*scrActions)[fontSizeName]->setTexts( tr("%1 pt").arg(font_sizes[s]));
 	}
 	(*scrActions)["fontSizeOther"]->setTexts( tr("&Other..."));
+
+	(*scrActions)["itemStyleSearch"]->setTexts( tr("Style &Search"));
+
 	(*scrActions)["alignLeft"]->setTexts( tr("&Left"));
 	(*scrActions)["alignCenter"]->setTexts( tr("&Center"));
 	(*scrActions)["alignRight"]->setTexts( tr("&Right"));
@@ -1945,6 +1953,7 @@ void ActionManager::createDefaultShortcuts()
 	defKeys.insert("itemRaiseToTop", Qt::Key_Home);
 	defKeys.insert("itemLower", Qt::CTRL | Qt::Key_End);
 	defKeys.insert("itemRaise", Qt::CTRL | Qt::Key_Home);
+	defKeys.insert("itemStyleSearch", Qt::CTRL | Qt::SHIFT | Qt::Key_Space);
 
 	//Insert Menu
 	//Page menu
diff --git a/scribus/scribus.cpp b/scribus/scribus.cpp
index bf92a7a1d..13c43dc54 100644
--- a/scribus/scribus.cpp
+++ b/scribus/scribus.cpp
@@ -146,6 +146,7 @@ for which a new license (GPL+exception) is in place.
 #include "selection.h"
 #include "serializer.h"
 #include "storyloader.h"
+#include "stylesearch.h"
 #include "textnote.h"
 #include "tocgenerator.h"
 #include "ui/about.h"
@@ -229,6 +230,7 @@ for which a new license (GPL+exception) is in place.
 #include "ui/smtextstyles.h"
 #include "ui/storyeditor.h"
 #include "ui/stylemanager.h"
+#include "ui/stylesearchdialog.h"
 #include "ui/symbolpalette.h"
 #include "ui/tabmanager.h"
 #include "ui/transformdialog.h"
@@ -1069,6 +1071,8 @@ void ScribusMainWindow::initMenuBar()
 
 	scrMenuMgr->createMenu("TextFeatures", tr("Text Features", "Item"));
 	scrMenuMgr->addMenuItemString("TextFeatures", "Item");
+	scrMenuMgr->addMenuItemString("itemStyleSearch", "TextFeatures");
+	scrMenuMgr->addMenuItemString("SEPARATOR", "TextFeatures");
 	scrMenuMgr->addMenuItemString("alignLeft", "TextFeatures");
 	scrMenuMgr->addMenuItemString("alignCenter", "TextFeatures");
 	scrMenuMgr->addMenuItemString("alignRight", "TextFeatures");
@@ -5111,6 +5115,32 @@ void ScribusMainWindow::slotResourceManager()
 	}
 }
 
+void ScribusMainWindow::slotItemStyleSearch()
+{
+	if (!HaveDoc)
+		return;
+
+	StyleSearch styleSearch(doc);
+	styleSearch.update();
+
+	if (!styleSearch.hasStyles())
+	{
+		return;
+	}
+
+	QScopedPointer<StyleSearchDialog> dialog(new StyleSearchDialog(this, styleSearch.getStyles()));
+	dialog->setModal(true);
+
+	int result = dialog->exec();
+	if (result != QDialog::Accepted)
+		return;
+
+	auto style = dialog->getStyle();
+	if (style.name.isEmpty())
+		return;
+	styleSearch.execute(style);
+}
+
 void ScribusMainWindow::ToggleTips()
 {
 	m_prefsManager.appPrefs.displayPrefs.showToolTips = scrActions["helpTooltips"]->isChecked();
diff --git a/scribus/scribus.h b/scribus/scribus.h
index 51b127d6c..7e368b681 100644
--- a/scribus/scribus.h
+++ b/scribus/scribus.h
@@ -408,6 +408,7 @@ public slots:
 	void slotOnlineHelp(const QString& jumpToSection = QString(), const QString& jumpToFile = QString());
 	void slotOnlineHelpClosed();
 	void slotResourceManager();
+	void slotItemStyleSearch();
 	void ToggleTips();
 	void ToggleMouseTips();
 	/** \brief Erzeugt eine neue Seite */
diff --git a/scribus/stylesearch.cpp b/scribus/stylesearch.cpp
new file mode 100644
index 000000000..7de184a3d
--- /dev/null
+++ b/scribus/stylesearch.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "stylesearch.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QList>
+#include <QStringList>
+
+#include "scribus.h"
+#include "selection.h"
+
+StyleSearch::StyleSearch(ScribusDoc *scribusDoc)
+	: scribusDoc{scribusDoc}
+{
+}
+
+void StyleSearch::update()
+{
+	if (scribusDoc->m_Selection->isEmpty())
+		return;
+	// TODO: we might simply accept that it's ok if there is a selection
+	// or if there is at least one text frame in the selection
+	// for (int i = 0; i < scribusDoc->m_Selection->count(); i++)
+	// {
+	// 	PageItem *currItem = scribusDoc->m_Selection->itemAt(i);
+	// 	if (currItem->isTextFrame())
+	// 	{
+	// 		textFrames.append(currItem->asTextFrame());
+	// 	}
+	// }
+
+	// if (textFrames.empty())
+	// 	return;
+
+	styles.clear();
+
+	int n = scribusDoc->paragraphStyles().count();
+	for (int i = 0; i < n; ++i )
+	{
+		auto style = scribusDoc->paragraphStyles()[i];
+		styles.append({style.name(), StyleSearchType::paragraph});
+	}
+	n = scribusDoc->charStyles().count();
+	for (int i = 0; i < n; ++i )
+	{
+		auto style = scribusDoc->charStyles()[i];
+		styles.append({style.name(), StyleSearchType::character});
+	}
+}
+
+/**
+ * The implementation execute is based on the scripter's scribus_setparagraphstyle
+ * and scribus_setcharstyle.
+ */
+void StyleSearch::execute(const StyleSearchItem& style)
+{
+	if (scribusDoc->m_Selection->isEmpty())
+		return;
+
+	if (style.type == StyleSearchType::paragraph)
+	{
+		if (!scribusDoc->paragraphStyles().contains(style.name))
+			return;
+
+		ParagraphStyle paragraphStyle;
+		paragraphStyle.setParent(style.name);
+		scribusDoc->itemSelection_ApplyParagraphStyle(paragraphStyle);
+	}
+	else if (style.type == StyleSearchType::character)
+	{
+		if (!scribusDoc->charStyles().contains(style.name))
+			return;
+
+		scribusDoc->itemSelection_SetNamedCharStyle(style.name);
+	}
+}
diff --git a/scribus/stylesearch.h b/scribus/stylesearch.h
new file mode 100644
index 000000000..f435eb754
--- /dev/null
+++ b/scribus/stylesearch.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef STYLESEARCH_H
+#define STYLESEARCH_H
+
+class QAction;
+class QMenu;
+class QMenuBar;
+
+#include <QList>
+#include <QHash>
+
+#include "scribusapi.h"
+#include "scribusdoc.h"
+
+enum class StyleSearchType { paragraph, character };
+
+struct StyleSearchItem
+{
+	QString name;
+	StyleSearchType type;
+};
+
+class SCRIBUS_API StyleSearch
+{
+public:
+	StyleSearch(ScribusDoc *scribusDoc);
+	~StyleSearch() = default;
+
+	const QList<StyleSearchItem>& getStyles() const { return styles; }
+
+	void update();
+	bool hasStyles() { return !styles.empty(); }
+	void execute(const StyleSearchItem& styleName);
+
+private:
+	ScribusDoc* scribusDoc;
+	QList<PageItem_TextFrame*> textFrames;
+	QList<StyleSearchItem> styles;
+};
+
+#endif
diff --git a/scribus/ui/applytemplatedialog.ui b/scribus/ui/applytemplatedialog.ui
new file mode 100644
index 000000000..615500932
--- /dev/null
+++ b/scribus/ui/applytemplatedialog.ui
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ApplyMasterPageDialog</class>
+ <widget class="QDialog" name="ApplyMasterPageDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>380</width>
+    <height>278</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Apply Master Page</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="masterPageLabel">
+       <property name="text">
+        <string>&amp;Master Page:</string>
+       </property>
+       <property name="buddy">
+        <cstring>masterPageComboBox</cstring>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QComboBox" name="masterPageComboBox"/>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="applyToPageButtonGroup">
+     <property name="title">
+      <string>Apply to</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <widget class="QRadioButton" name="currentPageRadioButton">
+        <property name="text">
+         <string>Current &amp;Page</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="evenPagesRadioButton">
+        <property name="text">
+         <string>&amp;Even Pages</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="oddPagesRadioButton">
+        <property name="text">
+         <string>O&amp;dd Pages</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="allPagesRadioButton">
+        <property name="text">
+         <string>&amp;All Pages</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QCheckBox" name="useRangeCheckBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>&amp;Within Range</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="ScrSpinBox" name="fromPageSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="decimals">
+           <number>0</number>
+          </property>
+          <property name="minimum">
+           <double>1.000000000000000</double>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="toPageLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>to</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="ScrSpinBox" name="toPageSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="decimals">
+           <number>0</number>
+          </property>
+          <property name="minimum">
+           <double>1.000000000000000</double>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QCheckBox" name="moveItemsCheckBox">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <property name="toolTip">
+        <string>All items on the page will be moved according to the displacement of the selected margin</string>
+       </property>
+       <property name="text">
+        <string>M&amp;ove Items with the</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="moveItemsAnchorComboBox">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="moveItemsMarginLabel">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="text">
+        <string>Margin</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ScrSpinBox</class>
+   <extends>QDoubleSpinBox</extends>
+   <header>ui/scrspinbox.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ApplyMasterPageDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ApplyMasterPageDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/scribus/ui/stylesearchdialog.cpp b/scribus/ui/stylesearchdialog.cpp
new file mode 100644
index 000000000..9dedb2bff
--- /dev/null
+++ b/scribus/ui/stylesearchdialog.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <utility>
+
+#include <QDebug>
+#include <QMainWindow>
+#include <QString>
+#include <QEvent>
+#include <QKeyEvent>
+
+#include "stylesearchdialog.h"
+#include "ui_stylesearchdialog.h"
+#include "iconmanager.h"
+
+StyleSearchDialog::StyleSearchDialog(QMainWindow *parent, const QList<StyleSearchItem>& styles) :
+	QDialog{parent},
+	ui{new Ui::StyleSearchDialog},
+	styles{styles}
+{
+	ui->setupUi(this);
+
+	ui->filterLineEdit->installEventFilter(this);
+	installEventFilter(this);
+
+	connect(ui->filterLineEdit, &QLineEdit::textChanged,      this, &StyleSearchDialog::updateList);
+	connect(this, &StyleSearchDialog::keyArrowUpPressed,     this, &StyleSearchDialog::moveSelectionUp);
+	connect(this, &StyleSearchDialog::keyArrowDownPressed,   this, &StyleSearchDialog::moveSelectionDown);
+	connect(ui->stylesListWidget, &QListWidget::itemDoubleClicked, this, &QDialog::accept);
+}
+
+StyleSearchDialog::~StyleSearchDialog()
+{
+	delete ui;
+}
+
+StyleSearchItem StyleSearchDialog::getStyle() const
+{
+	if (ui->stylesListWidget->count() == 0)
+		return {"", StyleSearchType::paragraph};
+
+	auto item = ui->stylesListWidget->currentItem();
+	return {item->text(), static_cast<StyleSearchType>(item->type() - 1000)};
+}
+
+/**
+ * @brief capture return, arrow keys, and tab
+ */
+bool StyleSearchDialog::eventFilter(QObject *obj, QEvent *event)
+{
+	if (obj == ui->filterLineEdit) {
+		if (event->type() == QEvent::KeyPress) {
+			return filterLineEditKeyPress(static_cast<QKeyEvent*>(event));
+		}
+	}
+	return false;
+}
+
+bool StyleSearchDialog::filterLineEditKeyPress(QKeyEvent * event)
+{
+	switch (event->key())
+	{
+		case Qt::Key_Enter:
+		case Qt::Key_Return:
+			this->accept();
+			return true;
+		case Qt::Key_Up:
+			emit keyArrowUpPressed();
+			return true;
+		case Qt::Key_Down:
+		case Qt::Key_Tab:
+			emit keyArrowDownPressed();
+			return true;
+		default:
+			return false;
+	}
+}
+
+void StyleSearchDialog::moveSelectionUp()
+{
+	int i = ui->stylesListWidget->currentRow();
+	if (i > 0)
+	{
+		ui->stylesListWidget->setCurrentRow(i - 1);
+	}
+}
+
+void StyleSearchDialog::moveSelectionDown()
+{
+	int i = ui->stylesListWidget->currentRow();
+	if (i < ui->stylesListWidget->count() - 1)
+		ui->stylesListWidget->setCurrentRow(i + 1);
+}
+
+
+/**
+ * Fill the list with all styles that match the filter.
+ * If the filter contains multiple words, acceppts all styles that
+ * contain all the words
+ */
+void StyleSearchDialog::updateList()
+{
+	ui->stylesListWidget->clear();
+
+	const auto filter = ui->filterLineEdit->text().trimmed();
+	if (filter.isEmpty())
+		return;
+
+	IconManager &iconManager = IconManager::instance();
+	QIcon iconParagraph;
+	iconParagraph.addPixmap(iconManager.loadPixmap("22/paragraph-style.png"));
+	QIcon iconCharacter;
+	iconCharacter.addPixmap(iconManager.loadPixmap("22/character-style.png"));
+	if (!filter.contains(" "))
+	{
+		for (auto& style: std::as_const(styles))
+		{
+			if (style.name.contains(filter, Qt::CaseInsensitive))
+			{
+				new QListWidgetItem(
+					style.type == StyleSearchType::paragraph ? iconParagraph : iconCharacter,
+					style.name,
+					ui->stylesListWidget,
+					1000 + static_cast<int>(style.type)
+				);
+			}
+		}
+	}
+
+	if (ui->stylesListWidget->count() > 0)
+		ui->stylesListWidget->setCurrentRow(0);
+}
diff --git a/scribus/ui/stylesearchdialog.h b/scribus/ui/stylesearchdialog.h
new file mode 100644
index 000000000..d14cba037
--- /dev/null
+++ b/scribus/ui/stylesearchdialog.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef STYLESEARCHDIALOG_H
+#define STYLESEARCHDIALOG_H
+
+class QKeyEvent;
+class QMainWindow;
+class QString;
+class QEvent;
+
+#include <QDialog>
+#include <QList>
+#include "stylesearch.h"
+
+namespace Ui { class StyleSearchDialog; }
+
+class StyleSearchDialog : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit StyleSearchDialog(QMainWindow *parent, const QList<StyleSearchItem> &styleNames);
+	~StyleSearchDialog();
+
+	StyleSearchItem getStyle() const;
+
+protected:
+	bool eventFilter(QObject *obj, QEvent *ev) override;
+
+private:
+	Ui::StyleSearchDialog *ui { nullptr };
+	QList<StyleSearchItem> styles;
+
+	bool filterLineEditKeyPress(QKeyEvent * event);
+
+private slots:
+	void moveSelectionUp();
+	void moveSelectionDown();
+	void updateList();
+
+signals:
+	void keyArrowUpPressed();
+	void keyArrowDownPressed();
+};
+
+#endif
diff --git a/scribus/ui/stylesearchdialog.ui b/scribus/ui/stylesearchdialog.ui
new file mode 100644
index 000000000..d60a4fbbd
--- /dev/null
+++ b/scribus/ui/stylesearchdialog.ui
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>StyleSearchDialog</class>
+ <widget class="QDialog" name="StyleSearchDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Style Search</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="leftMargin">
+    <number>9</number>
+   </property>
+   <property name="topMargin">
+    <number>9</number>
+   </property>
+   <property name="rightMargin">
+    <number>9</number>
+   </property>
+   <property name="bottomMargin">
+    <number>9</number>
+   </property>
+   <item>
+    <widget class="QLineEdit" name="filterLineEdit">
+     <property name="placeholderText">
+      <string>Search for style...</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QListWidget" name="stylesListWidget"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
style-search.diff (25,095 bytes)   

jghali

2024-02-17 01:30

administrator   ~0050998

I'm not sure how this could be faster than using style manager in "Apply Style" mode and right-clicking style then Apply. Or even using PP...

ale

2024-02-17 07:25

manager   ~0050999

this is about using the keyboard for applying the styles!
both ways of doing you're suggesting, imply reaching for the mouse.

if you choose wisely your style names, it's almost like using shortcut, except that:

- you don't have to assign shortcuts to the styles (and each document can have different style names)
- you don't have to come up with complex shortcuts (because all the good ones are already taken)
- you can be very idiomatic when applying shortcuts

applying the h1 styles is:

ctrl-shift-space h1 return

and you don't have to type the full name, any part of the style that matches is fine (and in the future it would nice to have some fuzzy matching too : - )

we could add this functionality to the action search, but i think that keeping them separated is the better choice.
most of all, if we can find a good way to add other formatting to this new tool.

i don't know if you're using visual studio code (or there is a similar feature in visual studio), but it's like using ctrl-p in there (and ctrl-shift-p).

ale

2024-06-21 08:16

manager   ~0051224

@jghali do you have any idea how scribus could better apply styles with the keyboard?

i have used this approach in the past and it was almost perfect for me... but there might be better ways to do it!

cbradney

2024-06-21 16:02

administrator   ~0051225

I like the option of having something like this. The hardest challenge for me is how to choose an appropriate keyboard shortcut to use given many in use by OSes, and the fact typing many non-Latin characters could conflict. Looks ok, I will test to see how it works.

Issue History

Date Modified Username Field Change
2024-02-16 19:55 ale New Issue
2024-02-16 19:55 ale Relationship added related to 0010289
2024-02-16 19:55 ale Note Added: 0050995
2024-02-16 19:55 ale File Added: apply-style-does-work.gif
2024-02-16 20:58 ale Note Added: 0050996
2024-02-16 20:58 ale File Added: style-search.diff
2024-02-16 20:59 ale Summary apply style "shortcuts" based on the "action search" tool => [PATCH] apply style "shortcuts" based on the "action search" tool
2024-02-16 20:59 ale Patch No => Yes
2024-02-17 01:30 jghali Note Added: 0050998
2024-02-17 07:25 ale Note Added: 0050999
2024-06-21 08:16 ale Note Added: 0051224
2024-06-21 16:02 cbradney Note Added: 0051225