add casts to zune macros to silence some warnings
[tangerine.git] / workbench / libs / popupmenu / pmlayout.c
blob5bc4468460637e985db87aa40c3d501ffaaf0c01
1 //
2 // PopupMenu
3 // ©1996-2000 Henrik Isaksson
4 //
5 // Menu Item Layout
6 //
8 #include "pmpriv.h"
10 UWORD PM_ItemHeight(struct PM_Window *a, struct PopupMenu *pm)
12 UWORD r,fonty=a->p->MenuFont->tf_YSize;
14 if(pm->Flags&NPM_HBAR_BIT) {
15 r=(UWORD)(PM_Prefs->pmp_YSpace*2+5);
16 pm->Flags|=NPM_FIXEDSIZE;
17 } else if(pm->Flags&NPM_WIDE_BAR_BIT) {
18 r=(UWORD)(PM_Prefs->pmp_YOffset*2+5);
19 pm->Flags|=NPM_FIXEDSIZE;
20 } else {
21 r=(UWORD)(fonty+1);
23 if(pm->Images[0]) { if(pm->Images[0]->Height>r) r=(UWORD)pm->Images[0]->Height+1; }
24 if(pm->Images[1]) { if(pm->Images[1]->Height>r) r=(UWORD)pm->Images[1]->Height+1; }
26 if(pm->Sub) {
27 UBYTE x=PM_Image_Height(a->p, PMIMG_SUBMENU, pm);
28 if(x>r) r=x;
29 } else if(pm->Flags&NPM_CHECKIT) {
30 UBYTE x=PM_Image_Height(a->p, pm->Exclude?PMIMG_EXCLUDE:PMIMG_CHECKMARK, pm);
31 if(x>r) r=x;
33 if(pm->CommKey!=0) {
34 UBYTE x=PM_Image_Height(a->p, PMIMG_AMIGAKEY, pm);
35 if(x>r) r=x;
38 r+=(UWORD)PM_Prefs->pmp_YSpace*2; // *2
41 return r;
44 UWORD PM_ItemWidth(struct PM_Window *a, struct PopupMenu *pm)
46 UWORD tmp=0,img=0,icn=0,fontx;
47 struct RastPort tmprp;
49 fontx=a->p->MenuFont->tf_XSize;
50 CopyMem(a->p->RootWnd->RPort, &tmprp, sizeof(struct RastPort));
51 tmprp.Font=a->p->MenuFont;
53 if(pm->Title) {
54 if(GET_TXTMODE(pm)==NPX_TXTBOOPSI) {
55 } else {
56 STRPTR title=pm->Title;
57 IPTR args[] = {(IPTR)pm->TitleID, 123};
58 if(GET_TXTMODE(pm)==NPX_TXTLOCALE) title=(STRPTR)CallHookA(a->p->LocaleHook, (Object *)pm, args);
60 if(title) tmp=TextLength(&tmprp,title,strlen(title));
64 if(pm->Flags&NPM_CHECKIT) {
65 tmp+=PM_Image_Width(a->p, pm->Exclude?PMIMG_EXCLUDE:PMIMG_CHECKMARK, pm);
66 tmp+=PM_Prefs->pmp_Intermediate;
67 } else if(pm->Sub && (a->p->PullDown==0) && (pm->Layout==0)) {
68 tmp+=PM_Image_Width(a->p, PMIMG_SUBMENU, pm);
69 tmp+=PM_Prefs->pmp_Intermediate;
72 if(pm->CommKey!=0) {
73 tmp+=PM_Image_Width(a->p, PMIMG_AMIGAKEY, pm);
74 tmp+=PM_Prefs->pmp_Intermediate+fontx*4;
77 if(pm->Flags&NPM_ISIMAGE) {
78 if(pm->Images[0]) img=pm->Images[0]->Width;
79 if(pm->Images[1]) if(pm->Images[1]->Width>img) img=pm->Images[1]->Width;
81 if(img>tmp) tmp=img;
82 } else {
83 struct Image *img=pm->Images[0];
85 // Hitta den största
87 if(!img) { img=pm->Images[1]; }
88 else if(pm->Images[1]) {
89 if(img->Width<pm->Images[1]->Width) img=pm->Images[1];
91 if(img) {
92 tmp+=PM_Prefs->pmp_Intermediate;
94 icn=img->Width+PM_Prefs->pmp_Intermediate;
96 if(icn>a->IconColumn) a->IconColumn=icn;
100 if(pm->Flags&NPM_COLOURBOX) {
101 if(!tmp) { // If there's no other stuff in the item, no intermediate spacing is req'd
102 tmp+=fontx*3;
103 tmp-=PM_Prefs->pmp_XSpace+2; // Must be like this for some unknow reason...
104 } else {
105 tmp+=PM_Prefs->pmp_Intermediate+fontx*3;
109 tmp+=PM_Prefs->pmp_XSpace*2; // "Horizontal spacing"
111 tmp+=2; // Item border
113 return (UWORD)(tmp);
117 void PM_CalcItemSize(struct PM_Window *a, struct PopupMenu *pm)
119 UWORD tmpw, tmph;
120 struct PopupMenu *p;
122 pm->Width=0;
123 pm->Height=0;
125 if(pm->Flags & NPM_HIDDEN) {
126 return;
129 if(pm->Flags & NPM_GROUP) {
131 // Calculate minimum size for each item.
132 // Calculate total size for the group.
135 p=pm->Sub;
136 tmpw=1;
137 tmph=1;
138 if(p) do {
139 PM_CalcItemSize(a, p);
141 if(!(p->Flags & NPM_HIDDEN)) {
142 if(pm->Layout==PML_Vertical) {
143 tmph+=p->Height;
144 if(p->Width>tmpw) tmpw=p->Width;
147 if(pm->Layout==PML_Horizontal) {
148 tmpw+=p->Width;
149 if(p->Height>tmph) tmph=p->Height;
154 p=p->Next;
155 } while(p);
156 } else {
157 struct PopupMenu *tmppm;
159 BOOL patched=FALSE;
161 tmppm=pm;
163 if(pm->Next) {
164 if((tmppm->Flags&NPM_NOSELECT) && (tmppm->Flags&NPM_SHADOWED) && !(tmppm->Flags&NPM_DISABLED) && (tmppm->Next->Flags&NPM_WIDE_BAR)) {
165 //PATCH(TP_CENTER, NPM_CENTERED);
167 PATCH(PMP_TITLE_UNDERLINE, NPM_UNDERLINEDTEXT);
168 PATCH(PMP_TITLE_BOLD, NPM_BOLDTEXT);
169 PATCH(PMP_TITLE_SHADOW, NPM_SHADOWED);
170 PATCH(PMP_TITLE_EMBOSS, NPM_EMBOSSED);
171 PATCH(PMP_TITLE_OUTLINE, NPM_OUTLINED);
173 //PATCH(TP_SHINE, NPM_SHINETEXT);
174 //PATCH(TP_SHADOW, NPM_SHADOWTEXT);
175 //PATCH(TP_HILITE, NPM_HILITETEXT);
177 patched=TRUE;
182 if(!patched) {
183 //TPATCH(TP_CENTER, NPM_CENTERED);
185 TPATCH(PMP_TEXT_UNDERLINE, NPM_UNDERLINEDTEXT);
186 TPATCH(PMP_TEXT_BOLD, NPM_BOLDTEXT);
187 TPATCH(PMP_TEXT_SHADOW, NPM_SHADOWED);
188 TPATCH(PMP_TEXT_EMBOSS, NPM_EMBOSSED);
189 TPATCH(PMP_TEXT_OUTLINE, NPM_OUTLINED);
191 //TPATCH(TP_SHINE, NPM_SHINETEXT);
192 //TPATCH(TP_SHADOW, NPM_SHADOWTEXT);
193 //TPATCH(TP_HILITE, NPM_HILITETEXT);
196 tmph=PM_ItemHeight(a, pm);
197 tmpw=PM_ItemWidth(a, pm);
200 pm->Height=tmph;
201 pm->Width=tmpw;
204 void PM_LayoutGroup(struct PM_Window *a, struct PopupMenu *pm)
206 UWORD tw, t, l, tsz, tmp;
207 struct PopupMenu *p;
208 BOOL restart;
210 // Is this a group? If not, return.
212 if(!(pm->Flags & NPM_GROUP))
213 return;
215 // Set up group offset
217 l=pm->Left;
218 t=pm->Top;
220 switch(pm->Layout) {
221 case PML_Vertical:
223 // Step 1. Calculate total weight.
224 // Hidden items and fixed size items are to be excluded from
225 // the size distribution, so they must be excluded from weight
226 // calculation aswell.
228 tw=0;
229 p=pm->Sub;
230 while(p) {
231 p->Flags&=~NPM_MINSIZE;
232 if(!(p->Flags & NPM_HIDDEN) && !(p->Flags&NPM_FIXEDSIZE)) {
233 tw++;
235 p=p->Next;
238 //kprintf("\n\nLAYOUT: Start. Maximum vertical size %ld\n", pm->Height);
240 //kprintf("LAYOUT: Initial vertical weight %ld\n", tw);
243 // Step 2. Find the items whose size is larger than what they
244 // would normally get if the available size was distributed
245 // equally.
248 do {
249 restart=FALSE;
251 // First we have to exclude fixed size items, and items that
252 // require more space than what equal distribution would
253 // result in.
254 tsz=pm->Height;
255 p=pm->Sub;
256 while(p) {
257 if(!(p->Flags & NPM_HIDDEN) && (p->Flags&NPM_FIXEDSIZE || p->Flags&NPM_MINSIZE))
258 tsz-=p->Height;
259 p=p->Next;
262 // Then we scan through the other items for those who require
263 // more space, and mark them with NPM_MINSIZE for exclusion
264 // in the loop above.
265 // If one, or more such items are found, we must repeat these
266 // steps once more, until there are no more such items left.
267 // (Until all remaining items can share the available space
268 // equally)
269 p=pm->Sub;
270 while(p) {
271 if(!(p->Flags & NPM_HIDDEN)) {
272 if(!(p->Flags & NPM_FIXEDSIZE) && !(p->Flags & NPM_MINSIZE)) {
273 if(tw) tmp=tsz/tw;
274 else tmp=0;
276 if(tmp<p->Height) {
277 p->Flags|=NPM_MINSIZE;
278 //kprintf("LAYOUT: Removed item %s (%ld > %ld)\n", p->Title, p->Height, tmp);
279 tw--;
280 restart=TRUE;
281 //break; // optimization, will require less looping
286 p=p->Next;
288 } while(restart);
290 //kprintf("LAYOUT: Remaining vertical size %ld\n", tsz);
291 //kprintf("LAYOUT: Remaining vertical weight %ld\n", tw);
294 // Step 3. Distribute the remaining size among the remaining items
295 // and position all items.
298 p=pm->Sub;
299 while(p) {
301 p->Width=pm->Width;
303 if(!(p->Flags & NPM_HIDDEN) && !(p->Flags&NPM_FIXEDSIZE) && !(p->Flags&NPM_MINSIZE)) {
304 if(tw) {
305 p->Height=tsz/tw; // Assign height
307 tsz-=p->Height; // This will avoid leaving an empty space at the end of a group,
308 tw--; // due to precision limitations when dividing integers.
312 p->Left=l; // Set item's
313 p->Top=t; // position
315 PM_LayoutGroup(a, p); // If this item is a group, layout will be handled here.
317 t+=p->Height;
318 p=p->Next;
320 break;
321 case PML_Horizontal:
323 // See PML_Vertical for explanations.
325 tw=0;
326 p=pm->Sub;
327 while(p) {
328 p->Flags&=~NPM_MINSIZE;
329 if(!(p->Flags & NPM_HIDDEN) && !(p->Flags&NPM_FIXEDSIZE)) {
330 tw++;
332 p=p->Next;
335 do {
336 restart=FALSE;
338 tsz=pm->Width;
339 p=pm->Sub;
340 while(p) {
341 if(!(p->Flags & NPM_HIDDEN) && (p->Flags&NPM_FIXEDSIZE || p->Flags&NPM_MINSIZE))
342 tsz-=p->Width;
343 p=p->Next;
346 p=pm->Sub;
347 while(p) {
348 if(!(p->Flags & NPM_HIDDEN)) {
349 if(!(p->Flags & NPM_FIXEDSIZE) && !(p->Flags & NPM_MINSIZE)) {
350 if(tw) tmp=tsz/tw;
351 else tmp=0;
353 if(tmp<p->Width) {
354 p->Flags|=NPM_MINSIZE;
355 tw--;
356 restart=TRUE;
361 p=p->Next;
363 } while(restart);
365 p=pm->Sub;
366 while(p) {
368 p->Height=pm->Height;
370 if(!(p->Flags & NPM_HIDDEN) && !(p->Flags&NPM_FIXEDSIZE) && !(p->Flags&NPM_MINSIZE)) {
371 if(tw) {
372 p->Width=tsz/tw; // Assign height
374 tsz-=p->Width; // This will avoid leaving an empty space at the end of a group,
375 tw--; // due to precision limitations when dividing integers.
379 p->Left=l; // Set item's
380 p->Top=t; // position
382 PM_LayoutGroup(a, p); // If this item is a group, layout will be handled here.
384 l+=p->Width;
385 p=p->Next;
387 break;
388 case PML_Table:
389 break;
393 void PM_LayoutMenu(struct PM_Window *a)
395 BOOL wb=PM_Prefs->pmp_PulldownPos==PMP_PD_WINDOWBAR;
398 // Calculate Item and Group sizes
400 PM_CalcItemSize(a, &a->PM);
401 a->PM.Width+=a->IconColumn;
403 // Set offsets
405 a->PM.Left=PM_Prefs->pmp_XOffset+a->p->BorderWidth;
406 a->PM.Top=PM_Prefs->pmp_YOffset+a->p->BorderHeight;
408 // Adjust for pulldowns
410 if(a->p->PullDown) {
412 if(a->p->RootWnd->BorderTop<10) wb=FALSE;
414 a->PM.Left=1;
415 a->PM.Top=1;
417 if(wb) {
418 a->PM.Height=a->p->RootWnd->BorderTop - 3;
421 if(!wb) {
422 a->PM.Height=a->p->RootWnd->WScreen->BarHeight - 2;
426 // Layout groups
428 PM_LayoutGroup(a, &a->PM);
430 // Set size of window
432 a->Height=a->PM.Height + (PM_Prefs->pmp_YOffset+a->p->BorderHeight)*2+1;
433 a->Width=a->PM.Width + (PM_Prefs->pmp_XOffset+a->p->BorderWidth)*2+1;
435 // Adjust for pulldowns
437 if(a->p->PullDown) {
439 if(wb) {
440 a->Height=a->p->RootWnd->BorderTop;
443 if(!wb) {
444 a->Height=a->p->RootWnd->WScreen->BarHeight+1;
447 if(wb) {
448 a->Width+=2; // 2 * borderwidth
449 if(a->Width<a->p->RootWnd->Width-1) {
450 a->Width=a->p->RootWnd->Width-1;
452 } else {
453 a->Width=a->p->RootWnd->WScreen->Width-1;