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