Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/libdraw/menuhit.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
#include <thread.h>
5
#include <mouse.h>
6
 
7
enum
8
{
9
	Margin = 4,		/* outside to text */
10
	Border = 2,		/* outside to selection boxes */
11
	Blackborder = 2,	/* width of outlining border */
12
	Vspacing = 2,		/* extra spacing between lines of text */
13
	Maxunscroll = 25,	/* maximum #entries before scrolling turns on */
14
	Nscroll = 20,		/* number entries in scrolling part */
15
	Scrollwid = 14,		/* width of scroll bar */
16
	Gap = 4,			/* between text and scroll bar */
17
};
18
 
19
static	Image	*menutxt;
20
static	Image	*back;
21
static	Image	*high;
22
static	Image	*bord;
23
static	Image	*text;
24
static	Image	*htext;
25
 
26
static
27
void
28
menucolors(void)
29
{
30
	/* Main tone is greenish, with negative selection */
31
	back = allocimagemix(display, DPalegreen, DWhite);
32
	high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen);	/* dark green */
33
	bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen);	/* not as dark green */
34
	if(back==nil || high==nil || bord==nil)
35
		goto Error;
36
	text = display->black;
37
	htext = back;
38
	return;
39
 
40
    Error:
41
	freeimage(back);
42
	freeimage(high);
43
	freeimage(bord);
44
	back = display->white;
45
	high = display->black;
46
	bord = display->black;
47
	text = display->black;
48
	htext = display->white;
49
}
50
 
51
/*
52
 * r is a rectangle holding the text elements.
53
 * return the rectangle, including its black edge, holding element i.
54
 */
55
static Rectangle
56
menurect(Rectangle r, int i)
57
{
58
	if(i < 0)
59
		return Rect(0, 0, 0, 0);
60
	r.min.y += (font->height+Vspacing)*i;
61
	r.max.y = r.min.y+font->height+Vspacing;
62
	return insetrect(r, Border-Margin);
63
}
64
 
65
/*
66
 * r is a rectangle holding the text elements.
67
 * return the element number containing p.
68
 */
69
static int
70
menusel(Rectangle r, Point p)
71
{
72
	r = insetrect(r, Margin);
73
	if(!ptinrect(p, r))
74
		return -1;
75
	return (p.y-r.min.y)/(font->height+Vspacing);
76
}
77
 
78
static
79
void
80
paintitem(Image *m, Menu *menu, Rectangle textr, int off, int i, int highlight, Image *save, Image *restore)
81
{
82
	char *item;
83
	Rectangle r;
84
	Point pt;
85
 
86
	if(i < 0)
87
		return;
88
	r = menurect(textr, i);
89
	if(restore){
90
		draw(m, r, restore, nil, restore->r.min);
91
		return;
92
	}
93
	if(save)
94
		draw(save, save->r, m, nil, r.min);
95
	item = menu->item? menu->item[i+off] : (*menu->gen)(i+off);
96
	pt.x = (textr.min.x+textr.max.x-stringwidth(font, item))/2;
97
	pt.y = textr.min.y+i*(font->height+Vspacing);
98
	draw(m, r, highlight? high : back, nil, pt);
99
	string(m, pt, highlight? htext : text, pt, font, item);
100
}
101
 
102
/*
103
 * menur is a rectangle holding all the highlightable text elements.
104
 * track mouse while inside the box, return what's selected when button
105
 * is raised, -1 as soon as it leaves box.
106
 * invariant: nothing is highlighted on entry or exit.
107
 */
108
static int
109
menuscan(Image *m, Menu *menu, int but, Mousectl *mc, Rectangle textr, int off, int lasti, Image *save)
110
{
111
	int i;
112
 
113
	paintitem(m, menu, textr, off, lasti, 1, save, nil);
114
	for(readmouse(mc); mc->buttons & (1<<(but-1)); readmouse(mc)){
115
		i = menusel(textr, mc->xy);
116
		if(i != -1 && i == lasti)
117
			continue;
118
		paintitem(m, menu, textr, off, lasti, 0, nil, save);
119
		if(i == -1)
120
			return i;
121
		lasti = i;
122
		paintitem(m, menu, textr, off, lasti, 1, save, nil);
123
	}
124
	return lasti;
125
}
126
 
127
static void
128
menupaint(Image *m, Menu *menu, Rectangle textr, int off, int nitemdrawn)
129
{
130
	int i;
131
 
132
	draw(m, insetrect(textr, Border-Margin), back, nil, ZP);
133
	for(i = 0; i<nitemdrawn; i++)
134
		paintitem(m, menu, textr, off, i, 0, nil, nil);
135
}
136
 
137
static void
138
menuscrollpaint(Image *m, Rectangle scrollr, int off, int nitem, int nitemdrawn)
139
{
140
	Rectangle r;
141
 
142
	draw(m, scrollr, back, nil, ZP);
143
	r.min.x = scrollr.min.x;
144
	r.max.x = scrollr.max.x;
145
	r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem;
146
	r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem;
147
	if(r.max.y < r.min.y+2)
148
		r.max.y = r.min.y+2;
149
	border(m, r, 1, bord, ZP);
150
	if(menutxt == 0)
151
		menutxt = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DDarkgreen);	/* border color; BUG? */
152
	if(menutxt)
153
		draw(m, insetrect(r, 1), menutxt, nil, ZP);
154
}
155
 
156
int
157
menuhit(int but, Mousectl *mc, Menu *menu, Screen *scr)
158
{
159
	int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem;
160
	int scrolling;
161
	Rectangle r, menur, sc, textr, scrollr;
162
	Image *b, *save, *backup;
163
	Point pt;
164
	char *item;
165
 
166
	if(back == nil)
167
		menucolors();
168
	sc = screen->clipr;
169
	replclipr(screen, 0, screen->r);
170
	maxwid = 0;
171
	for(nitem = 0;
172
	    item = menu->item? menu->item[nitem] : (*menu->gen)(nitem);
173
	    nitem++){
174
		i = stringwidth(font, item);
175
		if(i > maxwid)
176
			maxwid = i;
177
	}
178
	if(menu->lasthit<0 || menu->lasthit>=nitem)
179
		menu->lasthit = 0;
180
	screenitem = (Dy(screen->r)-10)/(font->height+Vspacing);
181
	if(nitem>Maxunscroll || nitem>screenitem){
182
		scrolling = 1;
183
		nitemdrawn = Nscroll;
184
		if(nitemdrawn > screenitem)
185
			nitemdrawn = screenitem;
186
		wid = maxwid + Gap + Scrollwid;
187
		off = menu->lasthit - nitemdrawn/2;
188
		if(off < 0)
189
			off = 0;
190
		if(off > nitem-nitemdrawn)
191
			off = nitem-nitemdrawn;
192
		lasti = menu->lasthit-off;
193
	}else{
194
		scrolling = 0;
195
		nitemdrawn = nitem;
196
		wid = maxwid;
197
		off = 0;
198
		lasti = menu->lasthit;
199
	}
200
	r = insetrect(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin);
201
	r = rectsubpt(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2));
202
	r = rectaddpt(r, mc->xy);
203
	pt = ZP;
204
	if(r.max.x>screen->r.max.x)
205
		pt.x = screen->r.max.x-r.max.x;
206
	if(r.max.y>screen->r.max.y)
207
		pt.y = screen->r.max.y-r.max.y;
208
	if(r.min.x<screen->r.min.x)
209
		pt.x = screen->r.min.x-r.min.x;
210
	if(r.min.y<screen->r.min.y)
211
		pt.y = screen->r.min.y-r.min.y;
212
	menur = rectaddpt(r, pt);
213
	textr.max.x = menur.max.x-Margin;
214
	textr.min.x = textr.max.x-maxwid;
215
	textr.min.y = menur.min.y+Margin;
216
	textr.max.y = textr.min.y + nitemdrawn*(font->height+Vspacing);
217
	if(scrolling){
218
		scrollr = insetrect(menur, Border);
219
		scrollr.max.x = scrollr.min.x+Scrollwid;
220
	}else
221
		scrollr = Rect(0, 0, 0, 0);
222
 
223
	if(scr){
224
		b = allocwindow(scr, menur, Refbackup, DWhite);
225
		if(b == nil)
226
			b = screen;
227
		backup = nil;
228
	}else{
229
		b = screen;
230
		backup = allocimage(display, menur, screen->chan, 0, -1);
231
		if(backup)
232
			draw(backup, menur, screen, nil, menur.min);
233
	}
234
	draw(b, menur, back, nil, ZP);
235
	border(b, menur, Blackborder, bord, ZP);
236
	save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1);
237
	r = menurect(textr, lasti);
238
	moveto(mc, divpt(addpt(r.min, r.max), 2));
239
	menupaint(b, menu, textr, off, nitemdrawn);
240
	if(scrolling)
241
		menuscrollpaint(b, scrollr, off, nitem, nitemdrawn);
242
	while(mc->buttons & (1<<(but-1))){
243
		lasti = menuscan(b, menu, but, mc, textr, off, lasti, save);
244
		if(lasti >= 0)
245
			break;
246
		while(!ptinrect(mc->xy, textr) && (mc->buttons & (1<<(but-1)))){
247
			if(scrolling && ptinrect(mc->xy, scrollr)){
248
				noff = ((mc->xy.y-scrollr.min.y)*nitem)/Dy(scrollr);
249
				noff -= nitemdrawn/2;
250
				if(noff < 0)
251
					noff = 0;
252
				if(noff > nitem-nitemdrawn)
253
					noff = nitem-nitemdrawn;
254
				if(noff != off){
255
					off = noff;
256
					menupaint(b, menu, textr, off, nitemdrawn);
257
					menuscrollpaint(b, scrollr, off, nitem, nitemdrawn);
258
				}
259
			}
260
			readmouse(mc);
261
		}
262
	}
263
	if(b != screen)
264
		freeimage(b);
265
	if(backup){
266
		draw(screen, menur, backup, nil, menur.min);
267
		freeimage(backup);
268
	}
269
	freeimage(save);
270
	replclipr(screen, 0, sc);
271
	flushimage(display, 1);
272
	if(lasti >= 0){
273
		menu->lasthit = lasti+off;
274
		return menu->lasthit;
275
	}
276
	return -1;
277
}