Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions TeXmacs/misc/pixmaps/liii-night/20x20/mode/left-align.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions TeXmacs/misc/pixmaps/liii-night/20x20/mode/middle-align.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions TeXmacs/misc/pixmaps/liii-night/20x20/mode/right-align.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions TeXmacs/misc/pixmaps/liii/20x20/mode/left-align.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions TeXmacs/misc/pixmaps/liii/20x20/mode/middle-align.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions TeXmacs/misc/pixmaps/liii/20x20/mode/right-align.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions TeXmacs/misc/themes/liii-night.css
Original file line number Diff line number Diff line change
Expand Up @@ -873,3 +873,28 @@ QWidget#centralWidget QWidget {
background: #202020;
color: #ffffff;
}

/*文本工具栏窗口样式*/
QWidget#text_toolbar {
background: #333333;
border: none;
border-radius: 8px;
}

/*文本工具栏按钮样式*/
QToolButton#text-toolbar-button {
background-color: transparent;
border: none;
}

/*文本工具栏按钮悬停样式*/
QToolButton#text-toolbar-button:hover {
background-color: rgba(255, 255, 255, 0.1);
border: none;
}

/*文本工具栏按钮按下样式*/
QToolButton#text-toolbar-button:pressed {
background-color: rgba(255, 255, 255, 0.2);
border: none;
}
25 changes: 25 additions & 0 deletions TeXmacs/misc/themes/liii.css
Original file line number Diff line number Diff line change
Expand Up @@ -850,3 +850,28 @@ QWidget#auxiliary_container {
#guestNotificationCloseButton:pressed {
background-color: rgba(0, 0, 0, 0.2);
}

/*文本工具栏窗口样式*/
QWidget#text_toolbar {
background: #ffffff;
border: none;
border-radius: 8px;
}

/*文本工具栏按钮样式*/
QToolButton#text-toolbar-button {
background-color: transparent;
border: none;
}

/*文本工具栏按钮悬停样式*/
QToolButton#text-toolbar-button:hover {
background-color: rgba(128, 128, 128, 0.3);
border: none;
}

/*文本工具栏按钮按下样式*/
QToolButton#text-toolbar-button:pressed {
background-color: rgba(128, 128, 128, 0.5);
border: none;
}
38 changes: 38 additions & 0 deletions TeXmacs/progs/generic/text-toolbar.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; MODULE : text-toolbar.scm
;; DESCRIPTION : text selection toolbar icons
;; COPYRIGHT : (C) 2026
;;
;; This software falls under the GNU general public license version 3 or later.
;; It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
;; in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(texmacs-module (generic text-toolbar)
(:use (generic format-edit)
(generic format-menu)
(generic generic-edit)))

(menu-bind text-toolbar-icons
((balloon (icon "tm_bold.xpm") "Write bold text")
(toggle-bold))
((balloon (icon "tm_italic.xpm") "Write italic text")
(toggle-italic))
((balloon (icon "tm_underline.xpm") "Write underline")
(toggle-underlined))
((balloon (icon "tm_marked.svg") "Marked text")
(mark-text))
(=> (balloon (icon "tm_color.xpm") "Select a foreground color")
(link color-menu))
(=> (balloon (icon "tm_section.xpm") "chapter::menu")
(link chapter-menu))
(=> (balloon (icon "tm_theorem.xpm") "enunciation")
(link enunciation-menu))
((balloon (icon "left-align.xpm") "left aligned")
(make-line-with "par-mode" "left"))
((balloon (icon "middle-align.xpm") "center")
(make-line-with "par-mode" "center"))
((balloon (icon "right-align.xpm") "right aligned")
(make-line-with "par-mode" "right")))
8 changes: 8 additions & 0 deletions devel/201_63.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# [201_63] 文字选中悬浮窗口初步实现

## 如何测试
1. 输入一段文字通过键盘或鼠标选中,会出现悬浮窗口
2. 依次点击悬浮窗口按钮,实现的功能和模式工具栏一致
3. 窗口位置的优先级应该是选区顶部>选区底部>窗口中央
4. 切换标签页不会导致原标签页的文本选中窗口失效
5. 单独选中任意数学公式环境该悬浮窗口都不出现,选中公式文本混合内容悬浮窗口出现
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个是出于什么目的?那代码块是不是也要判断 🤔

2 changes: 2 additions & 0 deletions src/Edit/Interface/edit_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,8 @@ edit_interface_rep::apply_changes () {
selection_rects= rs;
invalidate (selection_rects);
}
// 选区改变后更新文本工具栏
update_text_toolbar ();
}

// cout << "Handling alternative selection\n";
Expand Down
7 changes: 7 additions & 0 deletions src/Edit/Interface/edit_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ class edit_interface_rep : virtual public editor_rep {
void update_mouse_loci ();
void update_focus_loci ();
bool should_show_image_popup (tree t);
bool should_show_text_toolbar ();
rectangle get_text_selection_rect ();
void show_text_toolbar (rectangle selr, double magf, int scroll_x,
int scroll_y, int canvas_x, int canvas_y);
void hide_text_toolbar ();
bool is_point_in_text_toolbar (SI x, SI y);
void update_text_toolbar ();

/* the footer */
tree compute_text_footer (tree st);
Expand Down
2 changes: 2 additions & 0 deletions src/Edit/Interface/edit_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,8 @@ edit_interface_rep::handle_keypress (string key_u8, time_t t) {
if (!is_nil (focus_ids) && got_focus)
call ("link-follow-ids", object (focus_ids), object ("focus"));
notify_change (THE_DECORATIONS);
// 键盘事件后更新文本工具栏显示状态
update_text_toolbar ();
end_editing ();
// time_t t2= texmacs_time ();
// if (t2 - t1 >= 10) cout << "handle_keypress took " << t2-t1 << "ms\n";
Expand Down
125 changes: 122 additions & 3 deletions src/Edit/Interface/edit_mouse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "path.hpp"
#include "qapplication.h"
#include "qnamespace.h"
#include "qt_simple_widget.hpp"
#include "scheme.hpp"
#include "sys_utils.hpp"
#include "tm_buffer.hpp"
Expand Down Expand Up @@ -780,10 +781,14 @@ edit_interface_rep::mouse_any (string type, SI x, SI y, int mods, time_t t,
show_image_popup (tree_of_image_parent, selr, magf, get_scroll_x (),
get_scroll_y (), get_canvas_x (), get_canvas_y ());
}
hide_text_toolbar ();
}
else {
set_cursor_style ("normal");
hide_image_popup ();

// 检查是否应该显示文本工具栏
update_text_toolbar ();
}

if (type == "move") mouse_message ("move", x, y);
Expand Down Expand Up @@ -879,10 +884,14 @@ edit_interface_rep::mouse_any (string type, SI x, SI y, int mods, time_t t,
if (type == "press-up") mouse_scroll (x, y, true);
if (type == "press-down") mouse_scroll (x, y, false);

if ((type == "press-left") || (type == "release-left") ||
(type == "end-drag-left") || (type == "press-middle") ||
(type == "press-right"))
if ((type == "press-left") || (type == "press-middle") ||
(type == "press-right")) {
// 当用户点击其他地方(不在文本工具栏内)时,隐藏文本工具栏
if (!is_point_in_text_toolbar (x, y)) {
hide_text_toolbar ();
}
notify_change (THE_DECORATIONS);
}

if (type == "wheel" && N (data) == 2)
eval ("(wheel-event " * as_string (data[0]) * " " * as_string (data[1]) *
Expand Down Expand Up @@ -1014,3 +1023,113 @@ edit_interface_rep::handle_mouse (string kind, SI x, SI y, int m, time_t t,
}
handle_exceptions ();
}

/******************************************************************************
* Text toolbar support
******************************************************************************/

bool
edit_interface_rep::should_show_text_toolbar () {
if (as_bool (call ("in-math?")) || as_bool (call ("in-prog?")) ||
as_bool (call ("in-code?")) || as_bool (call ("in-verbatim?")))
return false;
// 检查是否有活动的文本选区
if (!selection_active_any ()) return false;

// 检查选区是否非空
tree sel_tree= selection_get ();
if (is_atomic (sel_tree) && as_string (sel_tree) == "") return false;

return true;
}

rectangle
edit_interface_rep::get_text_selection_rect () {
rectangle sel_rect;

if (selection_active_any () && !is_nil (selection_rects)) {
// 使用现有的选区矩形
sel_rect= least_upper_bound (selection_rects);
}
else if (selection_active_any ()) {
// 如果没有选区矩形,但选区存在,计算一个默认矩形
path p1, p2;
selection_get (p1, p2);
if (p1 != p2) {
selection sel= search_selection (p1, p2);
if (!is_nil (sel->rs)) {
sel_rect= least_upper_bound (sel->rs);
}
else {
// 如果选区矩形为空,使用光标位置创建一个最小矩形
cursor cu= get_cursor ();
sel_rect = rectangle (cu->ox - 10 * pixel, cu->oy - 5 * pixel,
cu->ox + 10 * pixel, cu->oy + 5 * pixel);
}
}
}

return sel_rect;
}
Comment on lines +1046 to +1073
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function can return an uninitialized rectangle if selection_active_any() returns false, or if selection_active_any() is true but selection_rects is nil and p1 == p2. This uninitialized rectangle could lead to undefined behavior when accessed in update_text_toolbar. The function should either initialize sel_rect with a default value at declaration or ensure all code paths properly initialize it.

Copilot uses AI. Check for mistakes.

void
edit_interface_rep::show_text_toolbar (rectangle selr, double magf,
int scroll_x, int scroll_y, int canvas_x,
int canvas_y) {
// 通过qt_simple_widget显示文本工具栏
// this指针实际上是edit_interface_rep,它继承自editor_rep,而editor_rep继承自simple_widget_rep
// 在Qt环境下,simple_widget_rep实际上是qt_simple_widget_rep
qt_simple_widget_rep* qsw= static_cast<qt_simple_widget_rep*> (this);
qsw->show_text_toolbar (selr, magf, scroll_x, scroll_y, canvas_x, canvas_y);
}

void
edit_interface_rep::hide_text_toolbar () {
// 通过qt_simple_widget隐藏文本工具栏
qt_simple_widget_rep* qsw= static_cast<qt_simple_widget_rep*> (this);
qsw->hide_text_toolbar ();
}

bool
edit_interface_rep::is_point_in_text_toolbar (SI x, SI y) {
// 通过qt_simple_widget检查点是否在文本工具栏内
qt_simple_widget_rep* qsw= static_cast<qt_simple_widget_rep*> (this);
return qsw->is_point_in_text_toolbar (x, y);
}

void
edit_interface_rep::update_text_toolbar () {
if (left_dragging) {
hide_text_toolbar ();
return;
}
// 检查是否应该显示文本工具栏
if (should_show_text_toolbar ()) {
rectangle text_selr= get_text_selection_rect ();
// 检查矩形是否有效(非零面积)
// 注意:rectangle 不是 list 类型,不能使用 is_nil
// 我们检查矩形坐标是否有效
if (text_selr->x1 < text_selr->x2 && text_selr->y1 < text_selr->y2) {
update_visible ();
SI sel_x1= min (text_selr->x1, text_selr->x2);
SI sel_x2= max (text_selr->x1, text_selr->x2);
SI sel_y1= min (text_selr->y1, text_selr->y2);
SI sel_y2= max (text_selr->y1, text_selr->y2);
bool sel_in_view=
!(sel_x2 < vx1 || sel_x1 > vx2 || sel_y2 < vy1 || sel_y1 > vy2);
if (!sel_in_view) {
hide_text_toolbar ();
return;
}
show_text_toolbar (text_selr, magf, get_scroll_x (), get_scroll_y (),
get_canvas_x (), get_canvas_y ());
}
else {
// 即使矩形无效,也尝试显示工具栏(例如单个字符选区)
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "即使矩形无效,也尝试显示工具栏(例如单个字符选区)" (Even if the rectangle is invalid, try to show the toolbar (e.g., single character selection)), but the code actually hides the toolbar when the rectangle is invalid. This is a contradiction - the comment should be corrected to match the actual behavior.

Suggested change
// 即使矩形无效,也尝试显示工具栏(例如单个字符选区
// 如果矩形无效,则隐藏工具栏(例如单个字符选区尚未形成有效矩形时

Copilot uses AI. Check for mistakes.
hide_text_toolbar ();
}
}
else {
hide_text_toolbar ();
}
}
Loading