登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
Gitee 年度开源项目评选结果正式揭晓,速戳👉
代码拉取完成,页面将自动刷新
开源项目
>
应用工具
>
文本编辑
&&
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
50
Star
305
Fork
92
GVP
墨干社区
/
墨干理工套件
代码
Issues
444
Pull Requests
17
Wiki
统计
流水线
服务
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
1163
[201_38] 图片支持鼠标移动和缩放
开启的
存在冲突
墨干社区:ty/120701
墨干社区:main
AcceleratorX
创建于 2025-12-07 14:08
克隆/下载
HTTPS
SSH
复制
下载 Email Patch
下载 Diff 文件
# [201_38] 图片支持鼠标移动和缩放 ## 如何测试 1. 打开 `TeXmacs/tests/tmu/201_38.tmu`,点击图片应该看到出现八个蓝色控制点 2. 左右拖动图片可以移动图片位置(目前上下移动图片有问题,这是因为图片碰撞箱模型用的是move_box而不是shift_box,我暂时不做模型的变更防止在其他某些地方出问题) 3. 拖动八个控制点可以调整图片的大小,应该符合主流编辑器的操作习惯(目前上面三个操作点的拖动有问题,这也是因为当前图片模型不支持上下移动) 4. 点击上下方文本,看图片上的蓝色控制点是否消失 5. 多次操作,检查操作点的绘制是否出现延迟或拖影 ## 2025/12/07 ### What 图片应该可以用鼠标来操作:放大、缩小、拖动等 之前的版本中只能调整上方的参数来改变图片的位置和大小,这样不够直观 ### How 注意到每次鼠标点击图片等控件(也就是在文本和图片来回切换或对图片直接操作)时都会触发 `edit_interface_rep::draw_selection`,故在这之后接入 `draw_resize_handles`,具体实现如下: ```cpp void edit_interface_rep::draw_resize_handles (renderer ren) { // Draw image resize handles when cursor is inside an image. SI hs = 10 * ren->pixel; // handle radius for visuals rectangle new_image_handles= rectangle (0, 0, 0, 0); SI x1= 0, y1= 0, x2= 0, y2= 0, mx= 0, my= 0; bool have_bbox= false; // Check if any ancestor of current path is an IMAGE for (path p= path_up (tp); !is_nil (p) && p != rp; p= path_up (p)) { tree st= subtree (et, p); if (!is_func (st, IMAGE)) continue; selection sel= eb->find_check_selection (p * 0, p * 1); if (!sel->valid || is_nil (sel->rs)) break; // image not drawable now rectangle bbox = least_upper_bound (sel->rs); x1 = bbox->x1; y1 = bbox->y1; x2 = bbox->x2; y2 = bbox->y2; mx = (x1 + x2) / 2; my = (y1 + y2) / 2; new_image_handles= rectangle (x1 - hs, y1 - hs, x2 + hs, y2 + hs); have_bbox = true; break; // only the closest IMAGE ancestor } if (new_image_handles != last_image_handles) { if (!is_zero (last_image_handles)) invalidate (last_image_handles); if (!is_zero (new_image_handles)) invalidate (new_image_handles); last_image_handles= new_image_handles; } if (!have_bbox) return; // nothing to draw // Draw 8 resize handles: 4 corners + 4 edge midpoints color handle_col= rgb_color (0, 120, 215); // Blue color ren->set_pencil (pencil (handle_col, ren->pixel)); ren->set_brush (brush (handle_col)); // Array of handle center positions: sw, se, nw, ne, s, n, w, e SI hx[8]= {x1, x2, x1, x2, mx, mx, x1, x2}; SI hy[8]= {y1, y1, y2, y2, y1, y2, my, my}; for (int i= 0; i < 8; i++) { SI cx= hx[i], cy= hy[i]; ren->fill_arc (cx - hs, cy - hs, cx + hs, cy + hs, 0, 64 * 360); ren->arc (cx - hs, cy - hs, cx + hs, cy + hs, 0, 64 * 360); } } ``` 绘制了八个操作点,用于图片的缩放。另外需要单独考虑更新逻辑,及时 invalidate 旧的 handles 并重绘 #### 为什么不在 `apply_changes` 里整体重新更新? 1. apply_changes 是一个大的更新引擎,频繁调用会影响性能开销,这种图像边框八个点的重绘没必要在这个大引擎中完成 2. apply_changes 存在一定的idle(可能是防止调用过于频繁而设置的,我试过放到这里面统一更新但发现“不跟手”),这点会导致移动图片时这八个操作点存在延迟,视觉上不美观。放在 draw_resize_handles 里单独处理非常迅速,开销小,功能耦合性低 并在前端对鼠标事件作出相应,及时更新图片的大小和位置,具体实现如下: ```scheme ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Image mouse dragging for moving and resizing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define image-drag-start-x #f) (define image-drag-start-y #f) (define image-resize-handle #f) (define image-resize-start-x #f) (define image-resize-start-y #f) (define image-resize-orig-w #f) (define image-resize-orig-h #f) (define image-resize-orig-xoff #f) (define image-resize-orig-yoff #f) (define (image-get-bbox t) (and-with rect (tree-bounding-rectangle t) (and (== (length rect) 4) rect))) (define image-handle-hitbox 6000) (define (image-point-on-handle? t) (and-with bbox (image-get-bbox t) (let* ((mpos (get-mouse-position)) (mx (car mpos)) (my (cadr mpos)) (x1 (car bbox)) (y1 (cadr bbox)) (x2 (caddr bbox)) (y2 (cadddr bbox)) (midx (/ (+ x1 x2) 2)) (midy (/ (+ y1 y2) 2)) (hs image-handle-hitbox) (near? (lambda (a b) (< (abs (- a b)) hs))) (handles `((nw ,x1 ,y2) (n ,midx ,y2) (ne ,x2 ,y2) (e ,x2 ,midy) (se ,x2 ,y1) (s ,midx ,y1) (sw ,x1 ,y1) (w ,x1 ,midy)))) (let loop ((hspec handles)) (if (null? hspec) #f (let* ((h (car hspec)) (hx (cadr h)) (hy (caddr h))) (if (and (near? mx hx) (near? my hy)) (car h) (loop (cdr hspec))))))))) (define (image-get-dimensions t) (let* ((w-str (tm->string (tree-ref t 1))) (h-str (tm->string (tree-ref t 2))) (w (and w-str (not (string-null? w-str)) (length-decode w-str))) (h (and h-str (not (string-null? h-str)) (length-decode h-str)))) (or (and w h (list w h)) (and-with bbox (image-get-bbox t) (list (- (caddr bbox) (car bbox)) (- (cadddr bbox) (cadr bbox))))))) (define (tmpt->cm v) (/ v 60472.0)) (define (cm->str v) (string-append (number->string v) "cm")) (define (image-set-size! t w h) (when (> w 0.1) (tree-set! t 1 (cm->str w))) (when (> h 0.1) (tree-set! t 2 (cm->str h))) (refresh-window)) (define (image-apply-resize t handle dx dy) (when (and image-resize-orig-w image-resize-orig-h) (let* ((ow (tmpt->cm image-resize-orig-w)) (oh (tmpt->cm image-resize-orig-h)) (sx (tmpt->cm dx)) (sy (tmpt->cm dy)) (nw (- ow sx)) (nh (- oh sy)) (xoff (or image-resize-orig-xoff 0)) (yoff (or image-resize-orig-yoff 0)) (set-xoff! (lambda () (tree-set! t 3 (cm->str (tmpt->cm (+ xoff dx)))))) (set-yoff! (lambda () (tree-set! t 4 (cm->str (tmpt->cm (- yoff dy))))))) (case handle ((se) (image-set-size! t (+ ow sx) (- oh sy))) ((sw) (when (> nw 0.1) (set-xoff!) (image-set-size! t nw (- oh sy)))) ((ne) (when (> nh 0.1) (set-yoff!) (image-set-size! t (+ ow sx) nh))) ((nw) (when (and (> nw 0.1) (> nh 0.1)) (set-xoff!) (set-yoff!) (image-set-size! t nw nh))) ((e) (when (> (+ ow sx) 0.1) (tree-set! t 1 (cm->str (+ ow sx))) (refresh-window))) ((w) (when (> nw 0.1) (set-xoff!) (tree-set! t 1 (cm->str nw)) (refresh-window))) ((n) (when (> nh 0.1) (set-yoff!) (tree-set! t 2 (cm->str nh)) (refresh-window))) ((s) (when (> (- oh sy) 0.1) (tree-set! t 2 (cm->str (- oh sy))) (refresh-window))))))) (define (image-apply-move t dx dy) (define (update-offset idx delta update-start!) (let* ((old (or (tm->string (tree-ref t idx)) "")) (delta-cm (cm->str (tmpt->cm delta))) (new-val (if (string-null? old) delta-cm (length-add old delta-cm)))) (tree-set! t idx new-val) (update-start!))) (let ((changed? #f)) (when (> (abs dx) 3000) (update-offset 3 dx (lambda () (set! image-drag-start-x (+ image-drag-start-x dx)))) (set! changed? #t)) (when (> (abs dy) 3000) (update-offset 4 (- dy) (lambda () (set! image-drag-start-y (+ image-drag-start-y dy)))) (set! changed? #t)) (when changed? (refresh-window)))) (define (image-reset-drag-state!) (set! image-drag-start-x #f) (set! image-drag-start-y #f) (set! image-resize-handle #f) (set! image-resize-start-x #f) (set! image-resize-start-y #f) (set! image-resize-orig-w #f) (set! image-resize-orig-h #f) (set! image-resize-orig-xoff #f) (set! image-resize-orig-yoff #f)) (define (image-decode-offset t idx) (let ((s (tm->string (tree-ref t idx)))) (if (and s (not (string-null? s))) (length-decode s) 0))) (tm-define (mouse-event key x y mods time data) (:require (and (tree-innermost image-context? #t) (in? key '("start-drag-left" "dragging-left" "end-drag-left")))) (and-with t (tree-innermost image-context? #t) (cond ((== key "start-drag-left") (image-reset-drag-state!) (let ((handle (image-point-on-handle? t))) (if handle (let ((dims (image-get-dimensions t))) (set! image-resize-handle handle) (set! image-resize-start-x x) (set! image-resize-start-y y) (set! image-resize-orig-w (if dims (car dims) 60472)) (set! image-resize-orig-h (if dims (cadr dims) 60472)) (set! image-resize-orig-xoff (image-decode-offset t 3)) (set! image-resize-orig-yoff (image-decode-offset t 4))) (begin (set! image-drag-start-x x) (set! image-drag-start-y y)))) (former key x y mods time data)) ((== key "dragging-left") (if image-resize-handle (when (and image-resize-start-x image-resize-start-y) (image-apply-resize t image-resize-handle (- x image-resize-start-x) (- y image-resize-start-y))) (when (and image-drag-start-x image-drag-start-y) (image-apply-move t (- x image-drag-start-x) (- y image-drag-start-y))))) ((== key "end-drag-left") (image-reset-drag-state!) (former key x y mods time data))))) ``` 这里涉及坐标换算和参数转换,较为复杂这里不赘述。 本质上就是前端根据鼠标的位置和移动参数设置图片的宽度、高度、X坐标、Y坐标
此 Pull Request 需要通过一些审核项
类型
指派人员
状态
审查
沈达
jingkaimori
章佳东
Yuki
MoonLL
JackYansongLi
进行中
(0/1人)
此 Pull Request 无法自动合并
尝试通过 WebIDE 解决冲突
怎样手动合并此 Pull Request
git checkout main
git pull https://gitee.com/MoganLab/mogan.git ty/120701
git push origin main
评论
1
提交
5
文件
5
检查
代码问题
0
批量操作
展开设置
折叠设置
审查
Code Owner
审查人员
jingkaimori
jingkaimori
gatsby
simplegatsby
Saidealem Eksan
saidealem-eksan
JACK
jack5261
hxh
wumo114514
xjl12
xjl12
沈达
da-liii
JackYansongLi
JackYansongLi
Yuki
lu-yifan227
AcceleratorX
AXeonV
章佳东
yinyuu
MoonLL
moonl313
未设置
最少人数
1
测试
jingkaimori
jingkaimori
gatsby
simplegatsby
Saidealem Eksan
saidealem-eksan
JACK
jack5261
hxh
wumo114514
xjl12
xjl12
沈达
da-liii
JackYansongLi
JackYansongLi
Yuki
lu-yifan227
AcceleratorX
AXeonV
章佳东
yinyuu
MoonLL
moonl313
未设置
最少人数
0
优先级
不指定
严重
主要
次要
不重要
标签
标签管理
未设置
关联 Issue
未关联
Pull Request 合并后将关闭上述关联 Issue
里程碑
未关联里程碑
Q&A
物理学幻灯片
v1.2.5 LTS
v1.2.7
v1.2.8
v1.2.9
v1.2.9.2
v1.2.9.3
v1.2.9.7
v2025.1.0
v2025.2.0
v2025.1.1
v2025.2.1
v2025.2.2
v2025.2.3
合并选项
合并后删除提交分支
提交分支为默认分支,无法删除
合并后关闭提到的 Issue
接受 Pull Request 时使用扁平化(Squash)合并
勾选此选项后,将建议使用 Squash Merge 方式合并以精简提交历史记录
参与者
(2)
C++
1
https://gitee.com/MoganLab/mogan.git
git@gitee.com:MoganLab/mogan.git
MoganLab
mogan
墨干理工套件
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册