Skip to content

Commit b55b9fb

Browse files
committed
refactor: integration of qt_completion_listbox
1 parent f7a6d02 commit b55b9fb

File tree

15 files changed

+438
-39
lines changed

15 files changed

+438
-39
lines changed

src/Edit/Interface/edit_complete.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/******************************************************************************
32
* MODULE : edit_complete.cpp
43
* DESCRIPTION: Tab completion
@@ -16,6 +15,7 @@
1615
#include "hashset.hpp"
1716
#include "iterator.hpp"
1817
#include "merge_sort.hpp"
18+
#include "message.hpp"
1919
#include "observers.hpp"
2020
#include "tree_observer.hpp"
2121

@@ -132,6 +132,34 @@ edit_interface_rep::complete_start (string prefix, array<string> compls) {
132132
completion_prefix= prefix;
133133
completions = close_completions (compls);
134134
completion_pos = 0;
135+
bool visible;
136+
SERVER (get_completion_listbox_visible (visible))
137+
if (!visible) {
138+
// TODO: refactor this part to edit_interface_rep::show_completion_listbox
139+
array<string> full_completions;
140+
for (int i= 0; i < N (completions); ++i) {
141+
string c= completions[i];
142+
if (c == completion_prefix) continue; // skip the prefix itself
143+
full_completions << (completion_prefix * c);
144+
}
145+
146+
path tp1= tp;
147+
for (int i= 0; i < N (prefix); ++i) {
148+
tp1= previous_valid (et, tp1);
149+
}
150+
151+
cursor cu= eb->find_check_cursor (tp1);
152+
// cout << "Prefix Cursor: " << cu->ox << ", " << cu->oy << LF;
153+
SI pos_x=
154+
((cu->ox - get_scroll_x () - 500) * magf + get_canvas_x ()) / 256;
155+
SI pos_y= -((cu->oy - 5000 - get_scroll_y ()) * magf) / 256;
156+
// TODO: 5000 is a magic number to add space between completion list box
157+
// and the text.
158+
// We need to find a better way to get the position
159+
160+
SERVER (show_completion_listbox (full_completions, pos_x, pos_y));
161+
}
162+
135163
insert_tree (completions[0]);
136164
complete_message ();
137165
beep ();
@@ -142,9 +170,17 @@ edit_interface_rep::complete_start (string prefix, array<string> compls) {
142170
bool
143171
edit_interface_rep::complete_keypress (string key) {
144172
set_message ("", "");
173+
cout << "complete_keypress: " << key << LF;
145174
if (key == "space") key= " ";
146-
if ((key != "tab") && (key != "S-tab")) {
175+
176+
if (key == "enter" || key == "return") {
177+
set_input_normal ();
178+
SERVER (set_completion_listbox_visible (false));
179+
return true;
180+
}
181+
if ((key != "tab") && (key != "S-tab") && (key != "up") && (key != "down")) {
147182
set_input_normal ();
183+
SERVER (set_completion_listbox_visible (false));
148184
return false;
149185
}
150186
tree st= subtree (et, path_up (tp));
@@ -161,10 +197,17 @@ edit_interface_rep::complete_keypress (string key) {
161197
return false;
162198
}
163199

164-
if (key == "tab") completion_pos++;
165-
else completion_pos--;
200+
if (key == "tab" || key == "down") {
201+
completion_pos++;
202+
SERVER (set_completion_listbox_next (true));
203+
}
204+
else if (key == "S-tab" || key == "up") {
205+
completion_pos--;
206+
SERVER (set_completion_listbox_next (false));
207+
}
166208
if (completion_pos < 0) completion_pos= N (completions) - 1;
167209
if (completion_pos >= N (completions)) completion_pos= 0;
210+
SERVER (set_completion_listbox_visible (true))
168211
string new_s= completions[completion_pos];
169212
remove (path_up (tp) * (end - N (old_s)), N (old_s));
170213
insert (path_up (tp) * (end - N (old_s)), new_s);

src/Graphics/Gui/message.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ enum slot_id {
5151
SLOT_VISIBLE_PART,
5252
SLOT_SCROLLBARS_VISIBILITY,
5353
SLOT_SCROLL_POSITION,
54+
SLOT_COMPLETION_LISTBOX_SHOW,
55+
SLOT_COMPLETION_LISTBOX_VISIBLE,
56+
SLOT_COMPLETION_LISTBOX_NEXT,
5457
SLOT_CANVAS,
5558
SLOT_SCROLLABLE,
5659
SLOT_CURSOR,
@@ -502,6 +505,27 @@ set_scroll_position (widget w, SI x, SI y) {
502505
send<SI, SI> (w, SLOT_SCROLL_POSITION, x, y);
503506
}
504507

508+
inline void
509+
show_completion_listbox (widget w, array<string>& completions, SI x, SI y) {
510+
send<array<string>, SI, SI> (w, SLOT_COMPLETION_LISTBOX_SHOW, completions, x,
511+
y);
512+
}
513+
514+
inline void
515+
get_completion_listbox_visible (widget w, bool& visible) {
516+
query<bool> (w, SLOT_COMPLETION_LISTBOX_VISIBLE);
517+
}
518+
519+
inline void
520+
set_completion_listbox_visible (widget w, bool visible) {
521+
send<bool> (w, SLOT_COMPLETION_LISTBOX_VISIBLE, visible);
522+
}
523+
524+
inline void
525+
set_completion_listbox_next (widget w, bool next) {
526+
send<bool> (w, SLOT_COMPLETION_LISTBOX_NEXT, next);
527+
}
528+
505529
inline void
506530
get_scroll_position (widget w, SI& x, SI& y) {
507531
// get scroll position in a canvas

src/Graphics/Gui/widget.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ slot_name (const slot s) {
4747
"SLOT_VISIBLE_PART",
4848
"SLOT_SCROLLBARS_VISIBILITY",
4949
"SLOT_SCROLL_POSITION",
50+
"SLOT_COMPLETION_LISTBOX_SHOW",
51+
"SLOT_COMPLETION_LISTBOX_VISIBLE",
52+
"SLOT_COMPLETION_LISTBOX_NEXT",
5053
"SLOT_CANVAS",
5154
"SLOT_SCROLLABLE",
5255
"SLOT_CURSOR",
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/******************************************************************************
2+
* MODULE : qt_completion_listbox.cpp
3+
* DESCRIPTION: Implementation of Completion ListBox widget for auto-completion
4+
* COPYRIGHT : (C) 2025 JimZhouZZY
5+
*******************************************************************************
6+
* This software falls under the GNU general public license version 3 or later.
7+
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
8+
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
9+
******************************************************************************/
10+
11+
#include "qt_completion_listbox.hpp"
12+
#include "QTMScrollView.hpp"
13+
#include "message.hpp"
14+
#include <QApplication>
15+
#include <QKeyEvent>
16+
#include <QScrollBar>
17+
18+
QtCompletionListBox::QtCompletionListBox (QWidget* parent)
19+
: QListWidget (parent), eventTarget (nullptr) {
20+
setWindowFlags (Qt::FramelessWindowHint |
21+
Qt::WindowStaysOnTopHint); // Qt::Window, Qt::Popup
22+
setFocusPolicy (Qt::NoFocus); // Qt::ClickFocus, Qt::StrongFocus
23+
setSelectionMode (QAbstractItemView::SingleSelection);
24+
setMouseTracking (true);
25+
26+
setStyleSheet ("QListWidget::item:selected {"
27+
" background-color: #3daee9;" // 蓝色背景
28+
" color: white;" // 白色文字
29+
"}"
30+
"QListWidget::item:hover {"
31+
" background-color: #93cee9;" // 浅蓝色悬停
32+
"}"
33+
"QListWidget {"
34+
" border: 1px solid #bfbfbf;"
35+
" background-color: white;"
36+
" alternate-background-color: #f0f0f0;"
37+
"}");
38+
39+
connect (this, &QListWidget::itemClicked, this,
40+
&QtCompletionListBox::onItemClicked);
41+
}
42+
43+
void
44+
QtCompletionListBox::showCompletions (array<string>& completions, SI x, SI y) {
45+
clear ();
46+
for (int i= 0; i < N (completions); ++i) {
47+
addItem (QString::fromUtf8 (as_charp (completions[i])));
48+
}
49+
if (N (completions) > 0) setCurrentRow (0);
50+
51+
QSize size (200, qMin (100, 20 + N (completions) * 22));
52+
QPoint topLeft (x, y);
53+
// qDebug () << "QtCompletionListBox::showCompletions: "
54+
// << "x=" << x << ", y=" << y << ", size=" << size.width () << "x"
55+
// << size.height () << Qt::endl;
56+
move (topLeft);
57+
resize (size);
58+
showComponent ();
59+
}
60+
61+
void
62+
QtCompletionListBox::showComponent () {
63+
// Ensure the listbox is visible
64+
show ();
65+
raise ();
66+
// activateWindow ();
67+
// setFocus (Qt::ActiveWindowFocusReason);
68+
}
69+
70+
void
71+
QtCompletionListBox::keyPressEvent (QKeyEvent* event) {
72+
return;
73+
}
74+
75+
void
76+
QtCompletionListBox::focusOutEvent (QFocusEvent* event) {
77+
hide ();
78+
QListWidget::focusOutEvent (event);
79+
}
80+
81+
void
82+
QtCompletionListBox::onItemClicked (QListWidgetItem* item) {
83+
if (item) {
84+
emit completionSelected (item->text ());
85+
hide ();
86+
}
87+
}
88+
89+
void
90+
QtCompletionListBox::wheelEvent (QWheelEvent* event) {
91+
QListWidget::wheelEvent (event);
92+
}
93+
94+
void
95+
QtCompletionListBox::selectNextItem () {
96+
int row= currentRow ();
97+
if (row < count () - 1) setCurrentRow (row + 1);
98+
else setCurrentRow (0);
99+
}
100+
101+
void
102+
QtCompletionListBox::selectPreviousItem () {
103+
int row= currentRow ();
104+
if (0 < row) setCurrentRow (row - 1);
105+
else setCurrentRow (count () - 1);
106+
}
107+
108+
void
109+
QtCompletionListBox::selectItemIndex (int index) {
110+
if (index >= 0 && index < count ()) {
111+
setCurrentRow (index);
112+
}
113+
else {
114+
// std::cerr << "Index out of bounds: " << index << std::endl;
115+
}
116+
}
117+
118+
void
119+
QtCompletionListBox::setEventTarget (QWidget* target) {
120+
eventTarget= target;
121+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/******************************************************************************
2+
* MODULE : qt_completion_listbox.hpp
3+
* DESCRIPTION: Completion ListBox widget for auto-completion
4+
* COPYRIGHT : (C) 2025 JimZhouZZY
5+
*******************************************************************************
6+
* This software falls under the GNU general public license version 3 or later.
7+
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
8+
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
9+
******************************************************************************/
10+
11+
#ifndef QT_COMPLETION_LISTBOX_HPP
12+
#define QT_COMPLETION_LISTBOX_HPP
13+
14+
#include "QTMScrollView.hpp"
15+
#include "array.hpp"
16+
#include <QListWidget>
17+
#include <QPoint>
18+
#include <QStringList>
19+
20+
class QtCompletionListBox : public QListWidget {
21+
Q_OBJECT
22+
public:
23+
void setAnchorUpdater (QTMScrollView* scrollarea,
24+
std::function<QPoint ()> anchorToScreenFunc);
25+
explicit QtCompletionListBox (QWidget* parent= nullptr);
26+
27+
void showCompletions (array<string>& completions, SI x, SI y);
28+
void selectNextItem ();
29+
void selectPreviousItem ();
30+
void selectItemIndex (int index);
31+
void setEventTarget (QWidget* target);
32+
void showComponent ();
33+
34+
signals:
35+
void completionSelected (const QString& text);
36+
37+
protected:
38+
void keyPressEvent (QKeyEvent* event) override;
39+
void focusOutEvent (QFocusEvent* event) override;
40+
void wheelEvent (QWheelEvent* event) override;
41+
42+
private:
43+
QWidget* eventTarget;
44+
45+
private slots:
46+
void onItemClicked (QListWidgetItem* item);
47+
};
48+
49+
#endif // QT_COMPLETION_LISTBOX_HPP

0 commit comments

Comments
 (0)