master
scrl.c
ohmu
·
2026-09-23
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <thread.h>
5#include <cursor.h>
6#include <mouse.h>
7#include <keyboard.h>
8#include <frame.h>
9#include <fcall.h>
10#include <plumb.h>
11#include <libsec.h>
12#include "dat.h"
13#include "fns.h"
14#include "parser.h"
15
16static Image *scrtmp;
17Image *scrollfg;
18Image *scrollborder;
19
20static
21Rectangle
22scrpos(Rectangle r, uint p0, uint p1, uint tot, int in)
23{
24 Rectangle q;
25 int h;
26
27 q = r;
28 if(in)
29 q = insetrect(r, 1); /* thumb lives inside the frame */
30 h = q.max.y-q.min.y;
31 if(tot == 0)
32 return q;
33 if(tot > 1024*1024){
34 tot>>=10;
35 p0>>=10;
36 p1>>=10;
37 }
38 if(p0 > 0)
39 q.min.y += h*p0/tot;
40 if(p1 < tot)
41 q.max.y -= h*(tot-p1)/tot;
42 if(q.max.y < q.min.y+2){
43 if(q.min.y+2 <= r.max.y)
44 q.max.y = q.min.y+2;
45 else
46 q.min.y = q.max.y-2;
47 }
48 return q;
49}
50
51void
52scrlresize(void)
53{
54 freeimage(scrtmp);
55 scrtmp = allocimage(display, Rect(0, 0, 32, screen->r.max.y), screen->chan, 0, DNofill);
56 if(scrtmp == nil)
57 error("scroll alloc");
58}
59
60void
61textscrdraw(Text *t)
62{
63 Rectangle r, r1, r2, r3;
64 Image *b, *tile;
65 int p92escrl;
66
67 p92escrl = (strcmp(scrollstyle, "p9-2e") == 0);
68
69 if(t->w==nil || t!=&t->w->body)
70 return;
71 if(scrtmp == nil)
72 scrlresize();
73 r = t->scrollr;
74 if(p92escrl)
75 r.min.x += 1; /* border between margin and bar */
76 b = scrtmp;
77 r1 = r;
78 r1.min.x = 0;
79 r1.max.x = Dx(r);
80 r2 = scrpos(r1, t->org, t->org+t->fr.nchars, t->file->b.nc, p92escrl);
81 if(!eqrect(r2, t->lastsr)){
82 t->lastsr = r2;
83 if(scrollborder == nil){
84 if(ispastel("scrlbord"))
85 scrollborder = allocimagemix(display, C_SCROLLBORDER, C_MIX);
86 else
87 scrollborder = allocimage(display, Rect(0,0,1,1), RGBA32, 1, C_SCROLLBORDER);
88 }
89 if(p92escrl){
90 /* frame, light grey trough, white thumb capped by scrollborder lines */
91 tile = tilebit(C_SCROLLTILEBG, "scrolltilebg", C_SCROLLTILEFG, "scrolltilefg");
92 draw(b, r1, scrollborder, nil, ZP);
93 draw(b, insetrect(r1, 1), tile, nil, ZP);
94 freeimage(tile);
95 draw(b, r2, t->fr.cols[BACK], nil, ZP);
96 r3 = r2;
97 r3.max.y = r3.min.y;
98 r3.min.y--;
99 draw(b, r3, scrollborder, nil, ZP);
100 r3 = r2;
101 r3.min.y = r3.max.y;
102 r3.max.y++;
103 draw(b, r3, scrollborder, nil, ZP);
104 /* the 1px gap left of the bar */
105 r3 = t->scrollr;
106 r3.max.x = r3.min.x+1;
107 draw(t->fr.b, r3, t->fr.cols[BACK], nil, ZP);
108 }else{
109 if(scrollfg == nil) {
110 if(ispastel("scrlfg"))
111 scrollfg = allocimagemix(display, C_SCROLLFG, C_MIX);
112 else
113 scrollfg = allocimage(display, Rect(0,0,1,1), RGBA32, 1, C_SCROLLFG);
114 }
115 draw(b, r1, t->fr.cols[BORD], nil, ZP);
116 draw(b, r2, scrollfg, nil, ZP);
117 r2.min.x = r2.max.x-1;
118 draw(b, r2, scrollborder, nil, ZP);
119 }
120 draw(t->fr.b, r, b, nil, Pt(0, r1.min.y));
121 }
122}
123
124void
125scrsleep(uint dt)
126{
127 Timer *timer;
128 static Alt alts[3];
129
130 timer = timerstart(dt);
131 alts[0].c = timer->c;
132 alts[0].v = nil;
133 alts[0].op = CHANRCV;
134 alts[1].c = mousectl->c;
135 alts[1].v = &mousectl->m;
136 alts[1].op = CHANRCV;
137 alts[2].op = CHANEND;
138 for(;;)
139 switch(alt(alts)){
140 case 0:
141 timerstop(timer);
142 return;
143 case 1:
144 timercancel(timer);
145 return;
146 }
147}
148
149void
150textscroll(Text *t, int but)
151{
152 uint p0, oldp0;
153 Rectangle s;
154 int x, y, my, h, first;
155
156 s = insetrect(t->scrollr, 1);
157 h = s.max.y-s.min.y;
158 x = (s.min.x+s.max.x)/2;
159 oldp0 = ~0;
160 first = TRUE;
161 do{
162 flushimage(display, 1);
163 my = mouse->xy.y;
164 if(my < s.min.y)
165 my = s.min.y;
166 if(my >= s.max.y)
167 my = s.max.y;
168 if(!eqpt(mouse->xy, Pt(x, my))){
169 moveto(mousectl, Pt(x, my));
170 readmouse(mousectl); /* absorb event generated by moveto() */
171 }
172 if(but == 2){
173 y = my;
174 p0 = (vlong)t->file->b.nc*(y-s.min.y)/h;
175 if(p0 >= t->q1)
176 p0 = textbacknl(t, p0, 2);
177 if(oldp0 != p0)
178 textsetorigin(t, p0, FALSE);
179 oldp0 = p0;
180 readmouse(mousectl);
181 continue;
182 }
183 if(but == 1)
184 p0 = textbacknl(t, t->org, (my-s.min.y)/t->fr.font->height);
185 else
186 p0 = t->org+frcharofpt(&t->fr, Pt(s.max.x, my));
187 if(oldp0 != p0)
188 textsetorigin(t, p0, TRUE);
189 oldp0 = p0;
190 /* debounce */
191 if(first){
192 flushimage(display, 1);
193 sleep(200);
194 nbrecv(mousectl->c, &mousectl->m);
195 first = FALSE;
196 }
197 scrsleep(80);
198 }while(mouse->buttons & (1<<(but-1)));
199 while(mouse->buttons)
200 readmouse(mousectl);
201}