temenuhit.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
temenuhit.c (7160B) | |
--- | |
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 t… | |
12 Maxunscroll = 25, /* maximum #entries before scrolling tu… | |
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);… | |
32 bord = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedgreen); … | |
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, Im… | |
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 la… | |
109 { | |
110 int i; | |
111 | |
112 paintitem(menu, textr, off, lasti, 1, save, nil); | |
113 flushimage(display, 1); /* in case display->locking is se… | |
114 *m = emouse(); | |
115 while(m->buttons & (1<<(but-1))){ | |
116 flushimage(display, 1); /* in case display->locki… | |
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… | |
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, screeni… | |
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)… | |
204 r = rectsubpt(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->h… | |
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, … | |
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-… | |
243 if(scrolling && ptinrect(m->xy, scrollr)){ | |
244 noff = ((m->xy.y-scrollr.min.y)*nitem)/D… | |
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, nite… | |
253 menuscrollpaint(scrollr, off, ni… | |
254 } | |
255 } | |
256 flushimage(display, 1); /* in case displa… | |
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 flushimage(display, 1); | |
266 if(lasti >= 0){ | |
267 menu->lasthit = lasti+off; | |
268 return menu->lasthit; | |
269 } | |
270 return -1; | |
271 } |