menuhit.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
menuhit.c (6868B) | |
--- | |
1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ | |
2 #include <u.h> | |
3 #include <libg.h> | |
4 #include "libgint.h" | |
5 | |
6 enum | |
7 { | |
8 Margin = 3, /* outside to text */ | |
9 Border = 2, /* outside to selection boxes */ | |
10 Blackborder = 1, /* width of outlining border */ | |
11 Vspacing = 1, /* 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 extern Bitmap *darkgrey; | |
19 | |
20 static int | |
21 fontheight() { | |
22 return font->ascent + font->descent; | |
23 } | |
24 | |
25 /* | |
26 * r is a rectangle holding the text elements. | |
27 * return the rectangle, including its black edge, holding element i. | |
28 */ | |
29 static Rectangle | |
30 menurect(Rectangle r, int i) | |
31 { | |
32 if(i < 0) | |
33 return Rect(0, 0, 0, 0); | |
34 r.min.y += (fontheight()+Vspacing)*i; | |
35 r.max.y = r.min.y+fontheight()+Vspacing; | |
36 return inset(r, Border-Margin); | |
37 } | |
38 | |
39 /* | |
40 * r is a rectangle holding the text elements. | |
41 * return the element number containing p. | |
42 */ | |
43 static int | |
44 menusel(Rectangle r, Point p) | |
45 { | |
46 if(!ptinrect(p, r)) | |
47 return -1; | |
48 return (p.y-r.min.y)/(fontheight()+Vspacing); | |
49 } | |
50 | |
51 /* | |
52 * menur is a rectangle holding all the highlightable text elements. | |
53 * track mouse while inside the box, return what's selected when button | |
54 * is raised, -1 as soon as it leaves box. | |
55 * invariant: nothing is highlighted on entry or exit. | |
56 */ | |
57 static int | |
58 menuscan(int but, Mouse *m, Rectangle menur, int lasti) | |
59 { | |
60 int i; | |
61 Rectangle r; | |
62 | |
63 r = menurect(menur, lasti); | |
64 bitblt(&screen, r.min, &screen, r, F&~D); | |
65 *m = emouse(); | |
66 while(m->buttons & (1<<(but-1))){ | |
67 *m = emouse(); | |
68 i = menusel(menur, m->xy); | |
69 if(i == lasti) | |
70 continue; | |
71 bitblt(&screen, r.min, &screen, r, F&~D); | |
72 if(i == -1) | |
73 return i; | |
74 r = menurect(menur, i); | |
75 bitblt(&screen, r.min, &screen, r, F&~D); | |
76 lasti = i; | |
77 } | |
78 return lasti; | |
79 } | |
80 | |
81 void | |
82 menupaint(Menu *menu, Rectangle textr, int off, int nitemdrawn) | |
83 { | |
84 int i; | |
85 Point pt; | |
86 Rectangle r; | |
87 char *item; | |
88 | |
89 r = inset(textr, Border-Margin); | |
90 bitblt(&screen, r.min, &screen, r, 0); | |
91 pt = Pt(textr.min.x+textr.max.x, textr.min.y); | |
92 for(i = 0; i<nitemdrawn; i++, pt.y += fontheight()+Vspacing){ | |
93 item = menu->item? menu->item[i+off] : (*menu->gen)(i+off); | |
94 string(&screen, | |
95 Pt((pt.x-strwidth(font, item))/2, pt.y), | |
96 font, item, S); | |
97 } | |
98 } | |
99 | |
100 static void | |
101 menuscrollpaint(Rectangle scrollr, int off, int nitem, int nitemdrawn) | |
102 { | |
103 Rectangle r; | |
104 | |
105 bitblt(&screen, scrollr.min, &screen, scrollr, 0); | |
106 r.min.x = scrollr.min.x; | |
107 r.max.x = scrollr.max.x; | |
108 r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem; | |
109 r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem; | |
110 if(r.max.y < r.min.y+2) | |
111 r.max.y = r.min.y+2; | |
112 border(&screen, r, 1, F, _bgpixel); | |
113 if(darkgrey) | |
114 texture(&screen, inset(r, 1), darkgrey, S); | |
115 } | |
116 | |
117 int | |
118 menuhit(int but, Mouse *m, Menu *menu) | |
119 { | |
120 int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; | |
121 bool scrolling; | |
122 Rectangle r, menur, sc, textr, scrollr; | |
123 Bitmap *b; | |
124 Point pt; | |
125 char *item; | |
126 extern unsigned int cursor; | |
127 unsigned int oldcursor = cursor; | |
128 | |
129 cursorswitch(ArrowCursor); | |
130 sc = screen.clipr; | |
131 clipr(&screen, screen.r); | |
132 maxwid = 0; | |
133 for(nitem = 0; | |
134 (item = menu->item? menu->item[nitem] : (*menu->gen)(nitem)); | |
135 nitem++){ | |
136 i = strwidth(font, item); | |
137 if(i > maxwid) | |
138 maxwid = i; | |
139 } | |
140 if(menu->lasthit<0 || menu->lasthit>=nitem) | |
141 menu->lasthit = 0; | |
142 screenitem = (Dy(screen.r)-10)/(fontheight()+Vspacing); | |
143 if(nitem>Maxunscroll || nitem>screenitem){ | |
144 scrolling = true; | |
145 nitemdrawn = Nscroll; | |
146 if(nitemdrawn > screenitem) | |
147 nitemdrawn = screenitem; | |
148 wid = maxwid + Gap + Scrollwid; | |
149 off = menu->lasthit - nitemdrawn/2; | |
150 if(off < 0) | |
151 off = 0; | |
152 if(off > nitem-nitemdrawn) | |
153 off = nitem-nitemdrawn; | |
154 lasti = menu->lasthit-off; | |
155 }else{ | |
156 scrolling = false; | |
157 nitemdrawn = nitem; | |
158 wid = maxwid; | |
159 off = 0; | |
160 lasti = menu->lasthit; | |
161 } | |
162 r = inset(Rect(0, 0, wid, nitemdrawn*(fontheight()+Vspacing)), -Marg… | |
163 r = rsubp(r, Pt(wid/2, lasti*(fontheight()+Vspacing)+fontheight()/2)… | |
164 r = raddp(r, m->xy); | |
165 pt = Pt(0, 0); | |
166 if(r.max.x>screen.r.max.x) | |
167 pt.x = screen.r.max.x-r.max.x; | |
168 if(r.max.y>screen.r.max.y) | |
169 pt.y = screen.r.max.y-r.max.y; | |
170 if(r.min.x<screen.r.min.x) | |
171 pt.x = screen.r.min.x-r.min.x; | |
172 if(r.min.y<screen.r.min.y) | |
173 pt.y = screen.r.min.y-r.min.y; | |
174 menur = raddp(r, pt); | |
175 textr.max.x = menur.max.x-Margin; | |
176 textr.min.x = textr.max.x-maxwid; | |
177 textr.min.y = menur.min.y+Margin; | |
178 textr.max.y = textr.min.y + nitemdrawn*(fontheight()+Vspacing); | |
179 if(scrolling){ | |
180 scrollr = inset(menur, Border); | |
181 scrollr.max.x = scrollr.min.x+Scrollwid; | |
182 }else | |
183 scrollr = Rect(0, 0, 0, 0); | |
184 | |
185 b = balloc(menur, screen.ldepth); | |
186 if(b == 0) | |
187 b = &screen; | |
188 bitblt(b, menur.min, &screen, menur, S); | |
189 bitblt(&screen, menur.min, &screen, menur, 0); | |
190 border(&screen, menur, Blackborder, F, _bgpixel); | |
191 r = menurect(textr, lasti); | |
192 cursorset(divpt(add(r.min, r.max), 2)); | |
193 menupaint(menu, textr, off, nitemdrawn); | |
194 if(scrolling) | |
195 menuscrollpaint(scrollr, off, nitem, nitemdrawn); | |
196 r = menurect(textr, lasti); | |
197 cursorset(divpt(add(r.min, r.max), 2)); | |
198 menupaint(menu, textr, off, nitemdrawn); | |
199 if(scrolling) | |
200 menuscrollpaint(scrollr, off, nitem, nitemdrawn); | |
201 while(m->buttons & (1<<(but-1))){ | |
202 lasti = menuscan(but, m, textr, lasti); | |
203 if(lasti >= 0) | |
204 break; | |
205 while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){ | |
206 if(scrolling && ptinrect(m->xy, scrollr)){ | |
207 noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); | |
208 noff -= nitemdrawn/2; | |
209 if(noff < 0) | |
210 noff = 0; | |
211 if(noff > nitem-nitemdrawn) | |
212 noff = nitem-nitemdrawn; | |
213 if(noff != off){ | |
214 off = noff; | |
215 menupaint(menu, textr, off, nitemdrawn); | |
216 menuscrollpaint(scrollr, off, nitem, nitemdrawn); | |
217 } | |
218 } | |
219 *m = emouse(); | |
220 } | |
221 } | |
222 bitblt(&screen, menur.min, b, menur, S); | |
223 if(b != &screen) | |
224 bfree(b); | |
225 clipr(&screen, sc); | |
226 if(lasti >= 0){ | |
227 menu->lasthit = lasti+off; | |
228 return cursorswitch(oldcursor), menu->lasthit; | |
229 } | |
230 cursorswitch(oldcursor); | |
231 return -1; | |
232 } |