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}