Subversion Repositories planix.SVN

Rev

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
#include <keyboard.h>
7
#include <control.h>
8
 
9
static int debug = 0;
10
 
11
typedef struct Text Text;
12
 
13
struct Text
14
{
15
	Control;
16
	int		border;
17
	int		topline;
18
	int		scroll;
19
	int		nvis;
20
	int		lastbut;
21
	CFont	*font;
22
	CImage	*image;
23
	CImage	*textcolor;
24
	CImage	*bordercolor;
25
	CImage	*selectcolor;
26
	CImage	*selectingcolor;
27
	Rune		**line;
28
	int		selectmode;	// Selsingle, Selmulti
29
	int		selectstyle;	// Seldown, Selup (use Selup only with Selsingle)
30
	uchar	*selected;
31
	int		nline;
32
	int		warp;
33
	int		align;
34
	int		sel;		// line nr of selection made by last button down
35
	int		but;		// last button down (still being hold)
36
	int		offsel;	// we are on selection
37
};
38
 
39
enum
40
{
41
	Selsingle,
42
	Selmulti,
43
	Seldown,
44
	Selup,
45
};
46
 
47
enum{
48
	EAccumulate,
49
	EAdd,
50
	EAlign,
51
	EBorder,
52
	EBordercolor,
53
	EClear,
54
	EDelete,
55
	EFocus,
56
	EFont,
57
	EHide,
58
	EImage,
59
	ERect,
60
	EReplace,
61
	EReveal,
62
	EScroll,
63
	ESelect,
64
	ESelectcolor,
65
	ESelectingcolor,
66
	ESelectmode,
67
	ESelectstyle,
68
	EShow,
69
	ESize,
70
	ETextcolor,
71
	ETopline,
72
	EValue,
73
	EWarp,
74
};
75
 
76
static char *cmds[] = {
77
	[EAccumulate] =	"accumulate",
78
	[EAdd] =			"add",
79
	[EAlign] =			"align",
80
	[EBorder] =		"border",
81
	[EBordercolor] =	"bordercolor",
82
	[EClear] =			"clear",
83
	[EDelete] =		"delete",
84
	[EFocus] = 		"focus",
85
	[EFont] =			"font",
86
	[EHide] =			"hide",
87
	[EImage] =		"image",
88
	[ERect] =			"rect",
89
	[EReplace] =		"replace",
90
	[EReveal] =		"reveal",
91
	[EScroll] =			"scroll",
92
	[ESelect] =		"select",
93
	[ESelectcolor] =	"selectcolor",
94
	[ESelectingcolor] =	"selectingcolor",
95
	[ESelectmode] =	"selectmode",
96
	[ESelectstyle] =		"selectstyle",
97
	[EShow] =			"show",
98
	[ESize] =			"size",
99
	[ETextcolor] =		"textcolor",
100
	[ETopline] =		"topline",
101
	[EValue] =			"value",
102
	[EWarp] =			"warp",
103
	nil
104
};
105
 
106
static void	textshow(Text*);
107
static void	texttogglei(Text*, int);
108
static int	textline(Text*, Point);
109
static int	texttoggle(Text*, Point);
110
 
111
static void
112
textmouse(Control *c, Mouse *m)
113
{
114
	Text *t;
115
	int sel;
116
 
117
	t = (Text*)c;
118
	if (debug) fprint(2, "textmouse %s t->lastbut %d; m->buttons %d\n", t->name, t->lastbut, m->buttons);
119
	if (t->warp >= 0)
120
		return;
121
	if ((t->selectstyle == Selup) && (m->buttons&7)) {
122
		sel = textline(t, m->xy);
123
		if (t->sel >= 0) {
124
//			if (debug) fprint(2, "textmouse Selup %q sel=%d t->sel=%d t->but=%d\n",
125
//						t->name, sel, t->sel, t->but);
126
			t->offsel = (sel == t->sel) ? 0 : 1;
127
			if ((sel == t->sel &&
128
				    ((t->selected[t->sel] && !t->but) ||
129
				     ((!t->selected[t->sel]) && t->but))) ||
130
			    (sel != t->sel &&
131
				     ((t->selected[t->sel] && t->but) ||
132
                                         ((!t->selected[t->sel]) && (!t->but))))) {
133
				texttogglei(t, t->sel);
134
			}
135
		}
136
	}
137
	if(t->lastbut != (m->buttons&7)){
138
		if(m->buttons & 7){
139
			sel = texttoggle(t, m->xy);
140
			if(sel >= 0) {
141
				if (t->selectstyle == Seldown) {
142
					chanprint(t->event, "%q: select %d %d",
143
						t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
144
					if (debug) fprint(2, "textmouse Seldown event %q: select %d %d\n",
145
						t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
146
				} else {
147
					if (debug) fprint(2, "textmouse Selup no event yet %q: select %d %d\n",
148
						t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
149
					t->sel = sel;
150
					t->but =  t->selected[sel] ? (m->buttons & 7) : 0;
151
				}
152
			}
153
		} else if (t->selectstyle == Selup) {
154
			sel = textline(t, m->xy);
155
			t->offsel = 0;
156
			if ((sel >= 0) && (sel == t->sel)) {
157
				chanprint(t->event, "%q: select %d %d",
158
					t->name, sel, t->but);
159
				if (debug) fprint(2, "textmouse Selup event %q: select %d %d\n",
160
					t->name, sel, t->but);
161
			} else if (sel != t->sel) {
162
				if  ((t->selected[t->sel] && t->but) ||
163
                                         ((!t->selected[t->sel]) && (!t->but))) {
164
					texttogglei(t, t->sel);
165
				} else {
166
					textshow(t);
167
				}
168
				if (debug) fprint(2, "textmouse Selup cancel %q: select %d %d\n",
169
					t->name, sel, t->but);
170
			}
171
			t->sel = -1;
172
			t->but = 0;
173
		}
174
		t->lastbut = m->buttons & 7;
175
	}
176
}
177
 
178
static void
179
textfree(Control *c)
180
{
181
	int i;
182
	Text *t;
183
 
184
	t = (Text*)c;
185
	_putctlfont(t->font);
186
	_putctlimage(t->image);
187
	_putctlimage(t->textcolor);
188
	_putctlimage(t->bordercolor);
189
	_putctlimage(t->selectcolor);
190
	_putctlimage(t->selectingcolor);
191
	for(i=0; i<t->nline; i++)
192
		free(t->line[i]);
193
	free(t->line);
194
	free(t->selected);
195
}
196
 
197
static void
198
textshow(Text *t)
199
{
200
	Rectangle r, tr;
201
	Point p;
202
	int i, ntext;
203
	Font *f;
204
	Rune *text;
205
 
206
	if (t->hidden)
207
		return;
208
	r = t->rect;
209
	f = t->font->font;
210
	draw(t->screen, r, t->image->image, nil, t->image->image->r.min);
211
	if(t->border > 0){
212
		border(t->screen, r, t->border, t->bordercolor->image, t->bordercolor->image->r.min);
213
		r = insetrect(r, t->border);
214
	}
215
	tr = r;
216
	t->nvis = Dy(r)/f->height;
217
	for(i=t->topline; i<t->nline && i<t->topline+t->nvis; i++){
218
		text = t->line[i];
219
		ntext = runestrlen(text);
220
		r.max.y = r.min.y+f->height;
221
		if(t->sel == i && t->offsel)
222
			draw(t->screen, r, t->selectingcolor->image, nil, ZP);
223
		else if(t->selected[i])
224
			draw(t->screen, r, t->selectcolor->image, nil, ZP);
225
		p = _ctlalignpoint(r,
226
			runestringnwidth(f, text, ntext),
227
			f->height, t->align);
228
		if(t->warp == i) {
229
			Point p2;
230
			 p2.x = p.x + 0.5*runestringnwidth(f, text, ntext);
231
			 p2.y = p.y + 0.5*f->height;
232
			moveto(t->controlset->mousectl, p2);
233
			t->warp = -1;
234
		}
235
		_string(t->screen, p, t->textcolor->image,
236
			ZP, f, nil, text, ntext, tr,
237
			nil, ZP, SoverD);
238
		r.min.y += f->height;
239
	}
240
	flushimage(display, 1);
241
}
242
 
243
static void
244
textctl(Control *c, CParse *cp)
245
{
246
	int cmd, i, n;
247
	Rectangle r;
248
	Text *t;
249
	Rune *rp;
250
 
251
	t = (Text*)c;
252
	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
253
	switch(cmd){
254
	default:
255
		ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
256
		break;
257
	case EAlign:
258
		_ctlargcount(t, cp, 2);
259
		t->align = _ctlalignment(cp->args[1]);
260
		break;
261
	case EBorder:
262
		_ctlargcount(t, cp, 2);
263
		if(cp->iargs[1] < 0)
264
			ctlerror("%q: bad border: %c", t->name, cp->str);
265
		t->border = cp->iargs[1];
266
		break;
267
	case EBordercolor:
268
		_ctlargcount(t, cp, 2);
269
		_setctlimage(t, &t->bordercolor, cp->args[1]);
270
		break;
271
	case EClear:
272
		_ctlargcount(t, cp, 1);
273
		for(i=0; i<t->nline; i++)
274
			free(t->line[i]);
275
		free(t->line);
276
		free(t->selected);
277
		t->line = ctlmalloc(sizeof(Rune*));
278
		t->selected = ctlmalloc(1);
279
		t->nline = 0;
280
		textshow(t);
281
		break;
282
	case EDelete:
283
		_ctlargcount(t, cp, 2);
284
		i = cp->iargs[1];
285
		if(i<0 || i>=t->nline)
286
			ctlerror("%q: line number out of range: %s", t->name, cp->str);
287
		free(t->line[i]);
288
		memmove(t->line+i, t->line+i+1, (t->nline-(i+1))*sizeof(Rune*));
289
		memmove(t->selected+i, t->selected+i+1, t->nline-(i+1));
290
		t->nline--;
291
		textshow(t);
292
		break;
293
	case EFocus:
294
		break;
295
	case EFont:
296
		_ctlargcount(t, cp, 2);
297
		_setctlfont(t, &t->font, cp->args[1]);
298
		break;
299
	case EHide:
300
		_ctlargcount(t, cp, 1);
301
		t->hidden = 1;
302
		break;
303
	case EImage:
304
		_ctlargcount(t, cp, 2);
305
		_setctlimage(t, &t->image, cp->args[1]);
306
		break;
307
	case ERect:
308
		_ctlargcount(t, cp, 5);
309
		r.min.x = cp->iargs[1];
310
		r.min.y = cp->iargs[2];
311
		r.max.x = cp->iargs[3];
312
		r.max.y = cp->iargs[4];
313
		if(Dx(r)<=0 || Dy(r)<=0)
314
			ctlerror("%q: bad rectangle: %s", t->name, cp->str);
315
		t->rect = r;
316
		t->nvis = (Dy(r)-2*t->border)/t->font->font->height;
317
		break;
318
	case EReplace:
319
		_ctlargcount(t, cp, 3);
320
		i = cp->iargs[1];
321
		if(i<0 || i>=t->nline)
322
			ctlerror("%q: line number out of range: %s", t->name, cp->str);
323
		free(t->line[i]);
324
		t->line[i] = _ctlrunestr(cp->args[2]);
325
		textshow(t);
326
		break;
327
	case EReveal:
328
		_ctlargcount(t, cp, 1);
329
		t->hidden = 0;
330
		textshow(t);
331
		break;
332
	case EScroll:
333
		_ctlargcount(t, cp, 2);
334
		t->scroll = cp->iargs[1];
335
		break;
336
	case ESelect:
337
		if(cp->nargs!=2 && cp->nargs!=3)
338
	badselect:
339
			ctlerror("%q: bad select message: %s", t->name, cp->str);
340
		if(cp->nargs == 2){
341
			if(strcmp(cp->args[1], "all") == 0){
342
				memset(t->selected, 1, t->nline);
343
				break;
344
			}
345
			if(strcmp(cp->args[1], "none") == 0){
346
				memset(t->selected, 0, t->nline);
347
				break;
348
			}
349
			if(cp->args[1][0]<'0' && '9'<cp->args[1][0])
350
				goto badselect;
351
			texttogglei(t, cp->iargs[1]);
352
			break;
353
		}
354
		if(cp->iargs[1]<0 || cp->iargs[1]>=t->nline)
355
			ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
356
		if(t->selected[cp->iargs[1]] != (cp->iargs[2]!=0))
357
			texttogglei(t, cp->iargs[1]);
358
		break;
359
	case ESelectcolor:
360
		_ctlargcount(t, cp, 2);
361
		_setctlimage(t, &t->selectcolor, cp->args[1]);
362
		break;
363
	case ESelectmode:
364
		_ctlargcount(t, cp, 2);
365
		if(strcmp(cp->args[1], "single") == 0)
366
			t->selectmode = Selsingle;
367
		else if(strncmp(cp->args[1], "multi", 5) == 0)
368
			t->selectmode = Selmulti;
369
		break;
370
	case ESelectstyle:
371
		_ctlargcount(t, cp, 2);
372
		 if(strcmp(cp->args[1], "down") == 0)
373
			t->selectstyle = Seldown;
374
		else if(strcmp(cp->args[1], "up") == 0)
375
			t->selectstyle = Selup;
376
		break;
377
	case EShow:
378
		_ctlargcount(t, cp, 1);
379
		textshow(t);
380
		break;
381
	case ESize:
382
		if (cp->nargs == 3)
383
			r.max = Pt(10000, 10000);
384
		else{
385
			_ctlargcount(t, cp, 5);
386
			r.max.x = cp->iargs[3];
387
			r.max.y = cp->iargs[4];
388
		}
389
		r.min.x = cp->iargs[1];
390
		r.min.y = cp->iargs[2];
391
		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)
392
			ctlerror("%q: bad sizes: %s", t->name, cp->str);
393
		t->size.min = r.min;
394
		t->size.max = r.max;
395
		break;
396
	case ETextcolor:
397
		_ctlargcount(t, cp, 2);
398
		_setctlimage(t, &t->textcolor, cp->args[1]);
399
		break;
400
	case ETopline:
401
		_ctlargcount(t, cp, 2);
402
		i = cp->iargs[1];
403
		if(i < 0)
404
			i = 0;
405
		if(i > t->nline)
406
			i = t->nline;
407
		if(t->topline != i){
408
			t->topline = i;
409
			textshow(t);
410
		}
411
		break;
412
	case EValue:
413
		/* set contents to single line */
414
		/* free existing text and fall through to add */
415
		for(i=0; i<t->nline; i++){
416
			free(t->line[i]);
417
			t->line[i] = nil;
418
		}
419
		t->nline = 0;
420
		t->topline = 0;
421
		/* fall through */
422
	case EAccumulate:
423
	case EAdd:
424
		switch (cp->nargs) {
425
		default:
426
			ctlerror("%q: wrong argument count in '%s'", t->name, cp->str);
427
		case 2:
428
			n = t->nline;
429
			break;
430
		case 3:
431
			n = cp->iargs[1];
432
			if(n<0 || n>t->nline)
433
				ctlerror("%q: line number out of range: %s", t->name, cp->str);
434
			break;
435
		}
436
		rp = _ctlrunestr(cp->args[cp->nargs-1]);
437
		t->line = ctlrealloc(t->line, (t->nline+1)*sizeof(Rune*));
438
		memmove(t->line+n+1, t->line+n, (t->nline-n)*sizeof(Rune*));
439
		t->line[n] = rp;
440
		t->selected = ctlrealloc(t->selected, t->nline+1);
441
		memmove(t->selected+n+1, t->selected+n, t->nline-n);
442
		t->selected[n] = (t->selectmode==Selmulti && cmd!=EAccumulate);
443
		t->nline++;
444
		if(t->scroll) {
445
			if(n > t->topline + (t->nvis - 1)){
446
				t->topline = n - (t->nvis - 1);
447
				if(t->topline < 0)
448
					t->topline = 0;
449
			}
450
			if(n < t->topline)
451
				t->topline = n;
452
		}
453
		if(cmd != EAccumulate)
454
			if(t->scroll || t->nline<=t->topline+t->nvis)
455
				textshow(t);
456
		break;
457
	case EWarp:
458
		_ctlargcount(t, cp, 2);
459
		i = cp->iargs[1];
460
		if(i <0 || i>=t->nline)
461
			ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
462
		if(i < t->topline || i >=  t->topline+t->nvis){
463
			t->topline = i;
464
		}
465
		t->warp = cp->iargs[1];
466
		textshow(t);
467
		t->warp = -1;
468
		break;
469
	}
470
}
471
 
472
static void
473
texttogglei(Text *t, int i)
474
{
475
	int prev;
476
 
477
	if(t->selectmode == Selsingle){
478
		/* clear the others */
479
		prev = t->selected[i];
480
		memset(t->selected, 0, t->nline);
481
		t->selected[i] = prev;
482
	}
483
	t->selected[i] ^= 1;
484
	textshow(t);
485
}
486
 
487
static int
488
textline(Text *t, Point p)
489
{
490
	Rectangle r;
491
	int i;
492
 
493
	r = t->rect;
494
	if(t->border > 0)
495
		r = insetrect(r, t->border);
496
	if(!ptinrect(p, r))
497
		return -1;
498
	i = (p.y-r.min.y)/t->font->font->height;
499
	i += t->topline;
500
	if(i >= t->nline)
501
		return -1;
502
	return i;
503
}
504
 
505
static int
506
texttoggle(Text *t, Point p)
507
{
508
	int i;
509
 
510
	i = textline(t, p);
511
	if (i >= 0)
512
		texttogglei(t, i);
513
	return i;
514
}
515
 
516
Control*
517
createtext(Controlset *cs, char *name)
518
{
519
	Text *t;
520
 
521
	t = (Text*)_createctl(cs, "text", sizeof(Text), name);
522
	t->line = ctlmalloc(sizeof(Rune*));
523
	t->selected = ctlmalloc(1);
524
	t->nline = 0;
525
	t->image = _getctlimage("white");
526
	t->textcolor = _getctlimage("black");
527
	t->bordercolor = _getctlimage("black");
528
	t->selectcolor = _getctlimage("yellow");
529
	t->selectingcolor = _getctlimage("paleyellow");
530
	t->font = _getctlfont("font");
531
	t->selectmode = Selsingle;
532
	t->selectstyle = Selup; // Seldown;
533
	t->lastbut = 0;
534
	t->mouse = textmouse;
535
	t->ctl = textctl;
536
	t->exit = textfree;
537
	t->warp = -1;
538
	t->sel = -1;
539
	t->offsel = 0;
540
	t->but = 0;
541
	return (Control *)t;
542
}