menuhit.c - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) 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)), -Margin);
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 }