Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | 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
#include <keyboard.h>
7
#include <control.h>
8
 
9
typedef struct Menu0 Menu0;	/* Menu is taken by mouse.h */
10
 
11
struct Menu0
12
{
13
	Control;
14
	CImage	*image;
15
	CImage	*bordercolor;
16
	CImage	*textcolor;
17
	CImage	*selectcolor;
18
	CImage	*selecttextcolor;
19
	CFont	*font;
20
	char		**line;
21
	int		nline;
22
	int		border;
23
	int		align;
24
	Image	*window;
25
	int		visible;	/* state of menu */
26
	int		selection;		/* currently selected line; -1 == none */
27
	int		prevsel;	/* previous selection */
28
	int		lastbut;	/* previous state of mouse button */
29
};
30
 
31
enum{
32
	EAdd,
33
	EAlign,
34
	EBorder,
35
	EBordercolor,
36
	EFocus,
37
	EFont,
38
	EFormat,
39
	EHide,
40
	EImage,
41
	ERect,
42
	EReveal,
43
	ESelectcolor,
44
	ESelecttextcolor,
45
	EShow,
46
	ESize,
47
	ETextcolor,
48
	EWindow,
49
};
50
 
51
static char *cmds[] = {
52
	[EAdd] = 			"add",
53
	[EAlign] = 			"align",
54
	[EBorder] = 		"border",
55
	[EBordercolor] =	"bordercolor",
56
	[EFocus] = 		"focus",
57
	[EFont] =			"font",
58
	[EFormat] = 		"format",
59
	[EHide] =			"hide",
60
	[EImage] =		"image",
61
	[ERect] =			"rect",
62
	[EReveal] =		"reveal",
63
	[ESelectcolor] =	"selectcolor",
64
	[ESelecttextcolor] =	"selecttextcolor",
65
	[EShow] =			"show",
66
	[ESize] =			"size",
67
	[ETextcolor] =		"textcolor",
68
	[EWindow] =		"window",
69
	nil
70
};
71
 
72
static void	menushow(Menu0*);
73
static void menuhide(Menu0*);
74
 
75
static void
76
menufree(Control *c)
77
{
78
	Menu0 *m;
79
 
80
	m = (Menu0*)c;
81
	_putctlfont(m->font);
82
	_putctlimage(m->image);
83
	_putctlimage(m->textcolor);
84
	_putctlimage(m->bordercolor);
85
	_putctlimage(m->selectcolor);
86
	_putctlimage(m->selecttextcolor);
87
}
88
 
89
static void
90
menushow(Menu0 *m)
91
{
92
	Rectangle r, clipr;
93
	int i, dx, dy, w;
94
	Font *f;
95
	Point p, q;
96
	Image *im, *c;
97
 
98
	if(m->hidden || m->window == nil)
99
		return;
100
 
101
	m->visible = 1;
102
	f = m->font->font;
103
	draw(m->window, m->rect, m->image->image, nil, m->image->image->r.min);
104
	if(m->border > 0)
105
		border(m->window, m->rect, m->border, m->bordercolor->image, ZP);
106
	/* text goes here */
107
	dx = 0;
108
	for(i=0; i<m->nline; i++){
109
		w = stringwidth(f, m->line[i]);
110
		if(dx < w)
111
			dx = w;
112
	}
113
	dy = m->nline*f->height;
114
	clipr = insetrect(m->rect, m->border);
115
	p = _ctlalignpoint(clipr, dx, dy, m->align);
116
	im = m->textcolor->image;
117
//	if(m->pressed)
118
//		im = m->pressedtextcolor->image;
119
	for(i=0; i<m->nline; i++){
120
		r.min = p;
121
		r.max.x = p.x+dx;
122
		r.max.y = p.y+f->height;
123
		c = im;
124
		if(i == m->selection){
125
			draw(m->window, r, m->selectcolor->image, nil, ZP);
126
			c = m->selecttextcolor->image;
127
		}
128
		q = _ctlalignpoint(r, stringwidth(f, m->line[i]), f->height, m->align%3);
129
		_string(m->window, q, c,
130
			ZP, f, m->line[i], nil, strlen(m->line[i]),
131
			clipr, nil, ZP, SoverD);
132
		p.y += f->height;
133
	}
134
//	if(m->pressed)
135
//		draw(m->screen, m->rect, m->lighm->image, m->mask->image, m->mask->image->r.min);
136
	flushimage(display, 1);
137
}
138
 
139
static Point
140
menusize(Menu0 *m)
141
{
142
	int x, y;
143
	int i;
144
	Point p;
145
	Font *f;
146
 
147
	x = 0;
148
	y = 0;
149
	f = m->font->font;
150
	for(i=0; i<m->nline; i++){
151
		p = stringsize(f, m->line[i]);
152
		if(p.x > x)
153
			x = p.x;
154
		y += f->height;
155
	}
156
 
157
	return Pt(x+2*m->border, y+2*m->border);
158
}
159
 
160
static void
161
menuhide(Menu0 *m)
162
{
163
	freeimage(m->window);
164
	m->window = nil;
165
	m->rect.max.y = m->rect.min.y;	/* go to zero size */
166
	m->lastbut = 0;
167
	m->visible = 0;
168
	if(m->selection >= 0)
169
		m->prevsel = m->selection;
170
	m->selection = -1;
171
	_ctlfocus(m, 0);
172
}
173
 
174
static void
175
menutrack(Control *c, Mouse *ms)
176
{
177
	Rectangle r;
178
	int s;
179
	Menu0 *m;
180
 
181
	m = (Menu0*)c;
182
	if(m->window == nil)
183
		return;
184
	if(m->lastbut && ms->buttons==0){	/* menu was released */
185
		chanprint(m->event, "%q: value %d", m->name, m->selection);
186
		menuhide(m);
187
		return;
188
	}
189
	m->lastbut = ms->buttons;
190
	r = insetrect(m->rect, m->border);
191
	if(!ptinrect(ms->xy, r))
192
		s = -1;
193
	else{
194
		s = (ms->xy.y - r.min.y)/m->font->font->height;
195
		if(s < 0 || s >= m->nline)
196
			s = -1;
197
	}
198
	if(m->visible== 0 || s!=m->selection){
199
		m->selection = s;
200
		menushow(m);
201
	}
202
}
203
 
204
static void
205
menuctl(Control *c, CParse *cp)
206
{
207
	int up, cmd, h;
208
	Rectangle r;
209
	Menu0 *m;
210
	Point diag;
211
 
212
	m = (Menu0*)c;
213
	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
214
	switch(cmd){
215
	default:
216
		ctlerror("%q: unrecognized message '%s'", m->name, cp->str);
217
		break;
218
	case EAdd:
219
		_ctlargcount(m, cp, 2);
220
		m->line = ctlrealloc(m->line, (m->nline+1)*sizeof(char*));
221
		m->line[m->nline++] = ctlstrdup(cp->args[1]);
222
		menushow(m);
223
		break;
224
	case EAlign:
225
		_ctlargcount(m, cp, 2);
226
		m->align = _ctlalignment(cp->args[1]);
227
		menushow(m);
228
		break;
229
	case EBorder:
230
		_ctlargcount(m, cp, 2);
231
		m->border = cp->iargs[1];
232
		menushow(m);
233
		break;
234
	case EBordercolor:
235
		_ctlargcount(m, cp, 2);
236
		_setctlimage(m, &m->bordercolor, cp->args[1]);
237
		menushow(m);
238
		break;
239
	case EFocus:
240
		_ctlargcount(m, cp, 2);
241
		if(atoi(cp->args[1]) == 0)
242
			menuhide(m);
243
		break;
244
	case EFont:
245
		_ctlargcount(m, cp, 2);
246
		_setctlfont(m, &m->font, cp->args[1]);
247
		break;
248
	case EFormat:
249
		_ctlargcount(m, cp, 2);
250
		m->format = ctlstrdup(cp->args[1]);
251
		break;
252
	case EHide:
253
		_ctlargcount(m, cp, 1);
254
		m->hidden = 1;
255
		break;
256
	case EImage:
257
		_ctlargcount(m, cp, 2);
258
		_setctlimage(m, &m->image, cp->args[1]);
259
		menushow(m);
260
		break;
261
	case ERect:
262
		_ctlargcount(m, cp, 5);
263
		r.min.x = cp->iargs[1];
264
		r.min.y = cp->iargs[2];
265
		r.max.x = cp->iargs[3];
266
		r.max.y = cp->iargs[4];
267
		if(Dx(r)<0 || Dy(r)<0)
268
			ctlerror("%q: bad rectangle: %s", m->name, cp->str);
269
		m->rect = r;
270
		menushow(m);
271
		break;
272
	case EReveal:
273
		_ctlargcount(m, cp, 1);
274
		m->hidden = 0;
275
		menushow(m);
276
		break;
277
	case ESelectcolor:
278
		_ctlargcount(m, cp, 2);
279
		_setctlimage(m, &m->selectcolor, cp->args[1]);
280
		menushow(m);
281
		break;
282
	case ESelecttextcolor:
283
		_ctlargcount(m, cp, 2);
284
		_setctlimage(m, &m->selecttextcolor, cp->args[1]);
285
		menushow(m);
286
		break;
287
	case EShow:
288
		_ctlargcount(m, cp, 1);
289
		menushow(m);
290
		break;
291
	case ESize:
292
		if (cp->nargs == 3)
293
			r.max = Pt(0x7fffffff, 0x7fffffff);
294
		else{
295
			_ctlargcount(m, cp, 5);
296
			r.max.x = cp->iargs[3];
297
			r.max.y = cp->iargs[4];
298
		}
299
		r.min.x = cp->iargs[1];
300
		r.min.y = cp->iargs[2];
301
		if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
302
			ctlerror("%q: bad sizes: %s", m->name, cp->str);
303
		m->size.min = r.min;
304
		m->size.max = r.max;
305
		break;
306
	case ETextcolor:
307
		_ctlargcount(m, cp, 2);
308
		_setctlimage(m, &m->textcolor, cp->args[1]);
309
		menushow(m);
310
		break;
311
	case EWindow:
312
		/* no args == toggle; otherwise 0 or 1 for state of window */
313
		if(cp->nargs >= 2)
314
			up = cp->iargs[1];
315
		else
316
			up = (m->window == nil);
317
		if(!up){	/* take window down */
318
			if(m->window)
319
				menuhide(m);
320
			break;
321
		}
322
		if(m->window != nil)
323
			break;
324
		diag = menusize(m);
325
		m->rect.max.x = m->rect.min.x + diag.x;
326
		m->rect.max.y = m->rect.min.y + diag.y;
327
		m->window = allocwindow(_screen, m->rect, Refbackup, DWhite);
328
		if(m->window == nil)
329
			m->window = m->screen;
330
		up = m->prevsel;
331
		if(up<0 || up>=m->nline)
332
			up = 0;
333
		m->selection = up;
334
		menushow(m);
335
		h = m->font->font->height;
336
		moveto(m->controlset->mousectl,
337
			Pt(m->rect.min.x+Dx(m->rect)/2, m->rect.min.y+up*h+h/2));
338
//		_ctlfocus(m, 1);
339
		break;
340
	}
341
}
342
 
343
Control*
344
createmenu(Controlset *cs, char *name)
345
{
346
	Menu0 *m;
347
 
348
	m = (Menu0*)_createctl(cs, "menu", sizeof(Menu0), name);
349
	m->font = _getctlfont("font");
350
	m->image = _getctlimage("white");
351
	m->textcolor = _getctlimage("black");
352
	m->selectcolor = _getctlimage("yellow");
353
	m->selecttextcolor = _getctlimage("black");
354
	m->bordercolor = _getctlimage("black");
355
	m->format = ctlstrdup("%q: value %d");
356
	m->border = 0;
357
	m->align = Aupperleft;
358
	m->visible = 0;
359
	m->window = nil;
360
	m->lastbut = 0;
361
	m->selection = -1;
362
	m->mouse = menutrack;
363
	m->ctl = menuctl;
364
	m->exit = menufree;
365
	return (Control *)m;
366
}