fix off-by-1 screen title fill
[AROS.git] / workbench / c / Decoration / screendecorclass.c
blob34def279b86f0db6cf9fba41f01fd14179f6e985
1 /*
2 Copyright 2011-2012, The AROS Development Team.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #include <clib/alib_protos.h>
11 #include <graphics/rpattr.h>
12 #include <proto/utility.h>
13 #include <proto/intuition.h>
14 #include <proto/graphics.h>
15 #include <proto/exec.h>
16 #include <string.h>
18 #include <intuition/cghooks.h>
20 #include "screendecorclass.h"
21 #include "drawfuncs.h"
22 #include "config.h"
24 #define SETIMAGE_SCR(id) sd->di->img_##id = CreateNewImageContainerMatchingScreen(data->di->img_##id, truecolor, screen)
26 #define CHILDPADDING 1
28 struct scrdecor_data
30 struct Screen *Screen;
31 /* These are original images loaded from disk */
32 struct DecorImages * di;
33 struct DecorConfig * dc;
34 Object *FirstChild;
37 static void DisposeScreenSkinning(struct scrdecor_data *data)
41 static BOOL InitScreenSkinning(struct scrdecor_data *data, struct DecorImages * di, struct DecorConfig * dc)
43 if ((!dc) || (!di))
44 return FALSE;
46 data->dc = dc;
47 data->di = di;
49 if (data->di->img_sdepth) return TRUE;
51 DisposeScreenSkinning(data);
52 return FALSE;
59 static IPTR scrdecor_new(Class *cl, Object *obj, struct opSet *msg)
61 struct scrdecor_data *data;
62 UWORD barh;
64 D(bug("scrdecor_new(tags @ 0x%p)\n", msg->ops_AttrList));
66 obj = (Object *)DoSuperMethodA(cl, obj, (Msg)msg);
68 if (obj)
70 data = INST_DATA(cl, obj);
72 struct DecorConfig * dc = (struct DecorConfig *) GetTagData(SDA_DecorConfig, (IPTR) NULL, msg->ops_AttrList);
73 struct DecorImages * di = (struct DecorImages *) GetTagData(SDA_DecorImages, (IPTR) NULL, msg->ops_AttrList);
75 D(bug("scrdecor_new: DecorImages @ 0x%p\n", di));
76 D(bug("scrdecor_new: DecorConfig @ 0x%p\n", dc));
78 data->FirstChild = NULL;
80 if (!InitScreenSkinning(data, di, dc))
82 CoerceMethod(cl,obj,OM_DISPOSE);
83 obj = NULL;
85 else
87 barh = data->dc->SBarHeight;
89 if (data->di->img_sbarlogo) if (data->di->img_sbarlogo->h > barh) barh = data->di->img_sbarlogo->h;
90 if (data->di->img_stitlebar) if (data->di->img_stitlebar->h > barh) barh = data->di->img_stitlebar->h;
93 return (IPTR)obj;
96 static IPTR scrdecor_dispose(Class *cl, Object *obj, struct opSet *msg)
98 struct scrdecor_data *data = INST_DATA(cl, obj);
100 DisposeScreenSkinning(data);
102 return 1;
105 /**************************************************************************************************/
107 static IPTR scrdecor_get(Class *cl, Object *obj, struct opGet *msg)
109 switch(msg->opg_AttrID)
111 case SDA_TrueColorOnly:
112 *msg->opg_Storage = TRUE;
113 break;
115 default:
116 return DoSuperMethodA(cl, obj, (Msg)msg);
118 return 1;
121 /**************************************************************************************************/
123 static void scr_findtitlearea(struct scrdecor_data *data, struct Screen *scr, LONG *left, LONG *right)
125 struct Gadget *g;
127 LONG minx = 0, maxx = scr->Width - 1;
129 for (g = scr->FirstGadget; g; g = g->NextGadget)
131 if (!(g->Flags & GFLG_RELRIGHT))
133 if (g->LeftEdge + g->Width > minx) minx = g->LeftEdge + g->Width;
135 else
137 if (g->LeftEdge + scr->Width - 1 - 1 < maxx) maxx = g->LeftEdge + scr->Width - 1 - 1;
140 if (maxx != scr->Width - 1)
141 maxx = maxx - (data->dc->SBarGadPre_s + data->dc->SBarGadPost_s);
143 *left = minx;
144 *right = maxx;
147 static IPTR scrdecor_set(Class *cl, Object *obj, struct opSet *msg)
149 struct scrdecor_data *data = INST_DATA(cl, obj);
150 struct TagItem *tags = msg->ops_AttrList;
151 struct TagItem *tstate;
152 struct TagItem *tag;
154 tstate = tags;
155 while ((tag = NextTagItem(&tstate)))
157 switch (tag->ti_Tag)
159 case SDA_TitleChild:
160 if (tag->ti_Data)
162 if (!(data->FirstChild))
164 LONG left, right = 0;
165 struct GadgetInfo childgadinf;
166 struct gpLayout childlayoutmsg;
167 D(bug("[screendecor] SDA_TitleChild: 0x%p\n", tag->ti_Data));
169 if ((childgadinf.gi_Screen = LockPubScreen(NULL)) != NULL)
171 UnlockPubScreen(NULL, childgadinf.gi_Screen);
172 data->FirstChild = (Object *)tag->ti_Data;
173 ((struct Gadget *)(data->FirstChild))->SpecialInfo = childgadinf.gi_Screen;
175 childgadinf.gi_RastPort = childgadinf.gi_Screen->BarLayer->rp;
177 if ((childgadinf.gi_DrInfo = GetScreenDrawInfo(childgadinf.gi_Screen)) != NULL)
179 childgadinf.gi_Pens.DetailPen = childgadinf.gi_DrInfo->dri_Pens[DETAILPEN];
180 childgadinf.gi_Pens.BlockPen = childgadinf.gi_DrInfo->dri_Pens[BLOCKPEN];
183 childlayoutmsg.MethodID = GM_LAYOUT;
184 childlayoutmsg.gpl_GInfo = &childgadinf;
185 childlayoutmsg.gpl_Initial = 0;
187 ((struct Gadget *)(data->FirstChild))->TopEdge = 0 + CHILDPADDING;
188 ((struct Gadget *)(data->FirstChild))->Height = childgadinf.gi_Screen->BarHeight - (CHILDPADDING << 1);
190 DoMethodA(data->FirstChild, &childlayoutmsg);
192 scr_findtitlearea(data, (childgadinf.gi_Screen), &left, &right);
194 ((struct Gadget *)(data->FirstChild))->LeftEdge = right - (((struct Gadget *)(data->FirstChild))->Width + data->dc->SBarGadPost_s + 1);
196 childlayoutmsg.MethodID = GM_GOACTIVE;
197 DoMethodA(data->FirstChild, &childlayoutmsg);
201 break;
202 default:
203 return DoSuperMethodA(cl, obj, (Msg)msg);
206 return 1;
209 static IPTR scrdecor_draw_screenbar(Class *cl, Object *obj, struct sdpDrawScreenBar *msg)
211 struct scrdecor_data *data = INST_DATA(cl, obj);
212 struct ScreenData *sd = (struct ScreenData *) msg->sdp_UserBuffer;
213 struct RastPort *rp = msg->sdp_RPort;
214 struct Screen *scr = msg->sdp_Screen;
215 struct DrawInfo *dri = msg->sdp_Dri;
216 UWORD *pens = dri->dri_Pens;
217 LONG left, right = 0, len, filllen;
218 BOOL beeping = scr->Flags & BEEPING;
220 if ((data->dc->SBarChildPre_s > 0) && (data->dc->SBarChildPre_s < sd->img_stitlebar->w))
221 filllen = data->dc->SBarChildPre_o;
222 else if ((data->dc->SBarGadPre_s > 0) && (data->dc->SBarGadPre_s < sd->img_stitlebar->w))
223 filllen = data->dc->SBarGadPre_o;
224 else
225 filllen = sd->img_stitlebar->w;
227 if (filllen == 0)
228 filllen = 1;
230 scr_findtitlearea(data, scr, &left, &right);
232 if (beeping)
234 SetAPen(rp, pens[BARDETAILPEN]);
235 RectFill(rp, 0, 0, scr->Width, sd->img_stitlebar->h);
237 else
239 if (sd->img_stitlebar->ok)
241 if (data->dc->SBarGadPre_s > 0)
243 WriteTiledImageHorizontal(rp, sd->img_stitlebar, 0,
244 data->dc->SBarGadPre_o, data->dc->SBarGadPre_s,
245 right + 1, 0, data->dc->SBarGadPre_o);
247 if (data->dc->SBarGadFill_s > 0)
249 WriteTiledImageHorizontal(rp, sd->img_stitlebar, 0,
250 data->dc->SBarGadFill_o, data->dc->SBarGadFill_s,
251 right + data->dc->SBarGadPre_s + 1, 0, scr->Width - (right + data->dc->SBarGadPre_s + data->dc->SBarGadPost_s));
253 if (data->dc->SBarGadPost_s > 0)
255 WriteTiledImageHorizontal(rp, sd->img_stitlebar, 0,
256 data->dc->SBarGadPost_o, data->dc->SBarGadPost_s,
257 scr->Width - data->dc->SBarGadPost_s, 0, data->dc->SBarGadPost_s);
261 if ((data->FirstChild) && (((struct Gadget *)(data->FirstChild))->Width > 2)) {
262 D(bug("[screendecor] draw_screenbar: titlechild width = %d\n", ((struct Gadget *)(data->FirstChild))->Width));
263 right = right - (((struct Gadget *)(data->FirstChild))->Width + data->dc->SBarChildPre_s + data->dc->SBarChildPost_s);
266 if (sd->img_stitlebar->ok)
268 WriteVerticalScaledTiledImageHorizontal(rp, sd->img_stitlebar, 0, 0,
269 filllen , 0, 0, data->dc->SBarHeight, right + 1, scr->BarHeight + 1);
274 if (sd->img_sbarlogo->ok)
276 WriteTiledImageHorizontal(rp, sd->img_sbarlogo, 0, 0,
277 sd->img_sbarlogo->w, data->dc->SLogoOffset,
278 (scr->BarHeight + 1 - sd->img_sbarlogo->h) / 2, sd->img_sbarlogo->w);
281 if (scr->Title != NULL)
283 struct TextExtent te;
285 len = strlen(scr->Title);
287 if ((len = TextFit(rp, scr->Title, len, &te, NULL, 1, right - data->dc->STitleOffset, scr->BarHeight)) != 0)
289 UWORD tx = data->dc->STitleOffset;
290 UWORD tymax = scr->BarHeight - (dri->dri_Font->tf_YSize - dri->dri_Font->tf_Baseline) - 1;
291 UWORD ty = ((scr->BarHeight + dri->dri_Font->tf_Baseline - 1) >> 1);
292 if (ty > tymax) ty = tymax;
294 SetFont(rp, msg->sdp_Dri->dri_Font);
295 SetDrMd(rp, JAM1);
297 if (!(sd->truecolor) || ((data->dc->STitleOutline == FALSE) && (data->dc->STitleShadow == FALSE)))
299 SetAPen(rp, pens[beeping ? BARBLOCKPEN : BARDETAILPEN]);
300 Move(rp, tx, ty);
301 Text(rp, scr->Title, len);
303 else if (data->dc->STitleOutline)
305 SetSoftStyle(rp, FSF_BOLD, AskSoftStyle(rp));
306 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorShadow, TAG_DONE);
308 Move(rp, tx + 1, ty ); Text(rp, scr->Title, len);
309 Move(rp, tx + 2, ty ); Text(rp, scr->Title, len);
310 Move(rp, tx , ty ); Text(rp, scr->Title, len);
311 Move(rp, tx, ty + 1); Text(rp, scr->Title, len);
312 Move(rp, tx, ty + 2); Text(rp, scr->Title, len);
313 Move(rp, tx + 1, ty + 2); Text(rp, scr->Title, len);
314 Move(rp, tx + 2, ty + 1); Text(rp, scr->Title, len);
315 Move(rp, tx + 2, ty + 2); Text(rp, scr->Title, len);
317 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorText, TAG_DONE);
318 Move(rp, tx + 1, ty + 1);
319 Text(rp, scr->Title, len);
320 SetSoftStyle(rp, FS_NORMAL, AskSoftStyle(rp));
322 else
324 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorShadow, TAG_DONE);
325 Move(rp, tx + 1, ty + 1 );
326 Text(rp, scr->Title, len);
328 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorText, TAG_DONE);
329 Move(rp, tx, ty);
330 Text(rp, scr->Title, len);
335 if (data->FirstChild && (((struct Gadget *)(data->FirstChild))->Width > 0)) {
336 struct GadgetInfo childgadinf;
337 struct gpRender childrendermsg =
339 GM_RENDER,
340 &childgadinf,
342 GREDRAW_REDRAW
345 if (sd->img_stitlebar->ok)
347 if (data->dc->SBarChildPre_s > 0)
349 WriteTiledImageHorizontal(rp, sd->img_stitlebar, 0,
350 data->dc->SBarChildPre_o, data->dc->SBarChildPre_s,
351 right + 1, 0, data->dc->SBarChildPre_s);
353 if (data->dc->SBarChildFill_s > 0)
355 WriteTiledImageHorizontal(rp, sd->img_stitlebar, 0,
356 data->dc->SBarChildFill_o, data->dc->SBarChildFill_s,
357 right + data->dc->SBarChildPre_s + 1, 0, ((struct Gadget *)(data->FirstChild))->Width);
359 else
361 WriteVerticalScaledTiledImageHorizontal(rp, sd->img_stitlebar, 0,
362 0, filllen , right + data->dc->SBarChildPre_s + 1, 0, data->dc->SBarHeight, right, scr->BarHeight + 1);
364 if (data->dc->SBarChildPost_s > 0)
366 WriteTiledImageHorizontal(rp, sd->img_stitlebar, 0,
367 data->dc->SBarChildPost_o, data->dc->SBarChildPost_s,
368 right + data->dc->SBarChildPre_s + ((struct Gadget *)(data->FirstChild))->Width + 1, 0, data->dc->SBarChildPost_s);
371 childgadinf.gi_Screen = ((struct Gadget *)(data->FirstChild))->SpecialInfo = scr;
372 childgadinf.gi_RastPort = rp;
373 childgadinf.gi_Pens.DetailPen = pens[DETAILPEN];
374 childgadinf.gi_Pens.BlockPen = pens[BLOCKPEN];
375 childgadinf.gi_DrInfo = dri;
376 childgadinf.gi_Domain.Left = right + data->dc->SBarChildPre_s + 1;
377 childgadinf.gi_Domain.Width = ((struct Gadget *)(data->FirstChild))->Width;
378 childgadinf.gi_Domain.Top = 0 + CHILDPADDING; // TODO: Get the real area from the theme..
379 childgadinf.gi_Domain.Height = sd->img_stitlebar->h - (CHILDPADDING << 1);
380 D(bug("[screendecor] draw_screenbar: rendering titlechild @ 0x%p, msg @ 0x%p, info @ 0x%p\n", data->FirstChild, &childrendermsg, &childgadinf));
381 DoMethodA(data->FirstChild, &childrendermsg);
384 return TRUE;
387 static IPTR scrdecor_getdefsize_sysimage(Class *cl, Object *obj, struct sdpGetDefSizeSysImage *msg)
389 struct scrdecor_data *data = INST_DATA(cl, obj);
391 if (msg->sdp_Which == SDEPTHIMAGE)
393 if (data->di && data->di->img_sdepth)
395 *msg->sdp_Height = data->di->img_sdepth->h;
396 *msg->sdp_Width = data->di->img_sdepth->w >> 1;
398 else return DoSuperMethodA(cl, obj, (Msg) msg);
400 else return DoSuperMethodA(cl, obj, (Msg) msg);
402 return TRUE;
405 static IPTR scrdecor_draw_sysimage(Class *cl, Object *obj, struct sdpDrawSysImage *msg)
407 struct ScreenData *sd = (struct ScreenData *) msg->sdp_UserBuffer;
409 struct RastPort *rp = msg->sdp_RPort;
410 LONG left = msg->sdp_X;
411 LONG top = msg->sdp_Y;
412 LONG width = msg->sdp_Width;
413 LONG height = msg->sdp_Height;
414 LONG state = msg->sdp_State;
416 if (msg->sdp_Which == SDEPTHIMAGE)
418 if (sd->img_sdepth)
420 DrawScaledStatefulGadgetImageToRP(rp, sd->img_sdepth, state, left, top, width, height);
422 else return DoSuperMethodA(cl, obj, (Msg) msg);
424 else return DoSuperMethodA(cl, obj, (Msg) msg);
426 return TRUE;
429 static IPTR scrdecor_layoutscrgadgets(Class *cl, Object *obj, struct sdpLayoutScreenGadgets *msg)
431 struct Gadget *gadget = msg->sdp_Gadgets;
432 struct ScreenData *sd = (struct ScreenData *) msg->sdp_UserBuffer;
434 struct scrdecor_data *data = INST_DATA(cl, obj);
436 while(gadget)
438 switch(gadget->GadgetType & GTYP_SYSTYPEMASK)
440 case GTYP_SDEPTH:
441 gadget->LeftEdge = -(gadget->Width + data->dc->SBarGadPost_s);
442 gadget->TopEdge = (data->dc->SBarHeight - sd->img_sdepth->h) >> 1;
443 gadget->Flags &= ~GFLG_RELWIDTH;
444 gadget->Flags |= GFLG_RELRIGHT;
445 break;
448 if (msg->sdp_Flags & SDF_LSG_MULTIPLE)
450 gadget = gadget->NextGadget;
452 else
454 gadget = NULL;
458 return TRUE;
461 static IPTR scrdecor_initscreen(Class *cl, Object *obj, struct sdpInitScreen *msg)
463 struct scrdecor_data *data = INST_DATA(cl, obj);
464 struct ScreenData *sd = (struct ScreenData *)msg->sdp_UserBuffer;
465 struct Screen *screen = msg->sdp_Screen;
467 sd->truecolor = msg->sdp_TrueColor;
469 BOOL truecolor = sd->truecolor;
472 * This depends on openwindow.c adding font height to w->BorderTop.
473 * It allows the window title bar to grow when font is bigger than decoration defined height
475 if ((msg->sdp_FontHeight + 2) > data->dc->BarHeight)
476 msg->sdp_WBorTop = 1;
477 else
478 msg->sdp_WBorTop = data->dc->BarHeight - 1 - msg->sdp_FontHeight;
480 /* Allow scaling title bar above decoration defined height */
481 msg->sdp_BarHeight = msg->sdp_FontHeight > (data->dc->SBarHeight - 1) ? msg->sdp_FontHeight : (data->dc->SBarHeight - 1);
483 msg->sdp_BarHBorder = 1;
484 msg->sdp_WBorLeft = data->dc->LeftBorder;
485 msg->sdp_WBorRight = data->dc->RightBorder;
486 msg->sdp_WBorBottom = data->dc->BottomBorder;
488 sd->ActivePen = -1;
489 sd->DeactivePen = -1;
490 #if 0 // Omitting this gives better colours on low-color screens
491 if (!truecolor) {
492 sd->ActivePen = ObtainPen(screen->ViewPort.ColorMap, -1, (data->dc->LUTBaseColors_a << 8) & 0xff000000, (data->dc->LUTBaseColors_a << 16) & 0xff000000, (data->dc->LUTBaseColors_a << 24) & 0xff000000, PEN_EXCLUSIVE);
493 sd->DeactivePen = ObtainPen(screen->ViewPort.ColorMap, -1, (data->dc->LUTBaseColors_d << 8) & 0xff000000, (data->dc->LUTBaseColors_d << 16) & 0xff000000, (data->dc->LUTBaseColors_d << 24) & 0xff000000, PEN_EXCLUSIVE);
495 #endif
497 /* Convert initial images to current screen */
498 /* Make sure a structure is always generated even if there is no image
499 That was the assumption of previous code :/ */
501 sd->di = NewImages();
503 SETIMAGE_SCR(sdepth);
504 SETIMAGE_SCR(sbarlogo);
505 SETIMAGE_SCR(stitlebar);
507 SETIMAGE_SCR(size);
508 SETIMAGE_SCR(close);
509 SETIMAGE_SCR(depth);
510 SETIMAGE_SCR(zoom);
511 SETIMAGE_SCR(up);
512 SETIMAGE_SCR(down);
513 SETIMAGE_SCR(left);
514 SETIMAGE_SCR(right);
515 SETIMAGE_SCR(mui);
516 SETIMAGE_SCR(popup);
517 SETIMAGE_SCR(snapshot);
518 SETIMAGE_SCR(iconify);
519 SETIMAGE_SCR(lock);
520 SETIMAGE_SCR(winbar_normal);
521 SETIMAGE_SCR(border_normal);
522 SETIMAGE_SCR(border_deactivated);
523 SETIMAGE_SCR(verticalcontainer);
524 SETIMAGE_SCR(verticalknob);
525 SETIMAGE_SCR(horizontalcontainer);
526 SETIMAGE_SCR(horizontalknob);
528 SETIMAGE_SCR(menu);
529 SETIMAGE_SCR(amigakey);
530 SETIMAGE_SCR(menucheck);
531 SETIMAGE_SCR(submenu);
533 /* Set pointers to converted images */
534 sd->img_sdepth = sd->di->img_sdepth;
535 sd->img_sbarlogo = sd->di->img_sbarlogo;
536 sd->img_stitlebar = sd->di->img_stitlebar;
538 sd->img_amigakey = sd->di->img_amigakey;
539 sd->img_menucheck = sd->di->img_menucheck;
540 sd->img_submenu = sd->di->img_submenu;
542 return TRUE;
545 static IPTR scrdecor_exitscreen(Class *cl, Object *obj, struct sdpExitScreen *msg)
547 struct ScreenData *sd = (struct ScreenData *)msg->sdp_UserBuffer;
549 FreeImages(sd->di);
551 return TRUE;
554 /**************************************************************************************************/
556 static IPTR scrdecor_dispatcher(struct IClass *cl, Object *obj, Msg msg)
558 IPTR retval;
560 switch(msg->MethodID)
562 case OM_NEW:
563 retval = scrdecor_new(cl, obj, (struct opSet *)msg);
564 break;
566 case OM_DISPOSE:
567 retval = scrdecor_dispose(cl, obj, (struct opSet *)msg);
568 break;
570 case OM_GET:
571 retval = scrdecor_get(cl, obj, (struct opGet *)msg);
572 break;
574 case OM_SET:
575 retval = scrdecor_set(cl, obj, (struct opSet *)msg);
576 break;
578 case SDM_GETDEFSIZE_SYSIMAGE:
579 retval = scrdecor_getdefsize_sysimage(cl, obj, (struct sdpGetDefSizeSysImage *)msg);
580 break;
582 case SDM_DRAW_SCREENBAR:
583 retval = scrdecor_draw_screenbar(cl, obj, (struct sdpDrawScreenBar *)msg);
584 break;
586 case SDM_DRAW_SYSIMAGE:
587 retval = scrdecor_draw_sysimage(cl, obj, (struct sdpDrawSysImage *)msg);
588 break;
590 case SDM_LAYOUT_SCREENGADGETS:
591 retval = scrdecor_layoutscrgadgets(cl, obj, (struct sdpLayoutScreenGadgets *)msg);
592 break;
594 case SDM_INITSCREEN:
595 retval = scrdecor_initscreen(cl, obj, (struct sdpInitScreen *)msg);
596 break;
598 case SDM_EXITSCREEN:
599 retval = scrdecor_exitscreen(cl, obj, (struct sdpExitScreen *)msg);
600 break;
602 default:
603 retval = DoSuperMethodA(cl, obj, msg);
604 break;
607 return retval;
610 struct IClass * MakeScreenDecorClass()
612 struct IClass * cl = MakeClass(NULL, SCRDECORCLASS, NULL, sizeof(struct scrdecor_data), 0);
613 if (cl)
615 cl->cl_Dispatcher.h_Entry = HookEntry;
616 cl->cl_Dispatcher.h_SubEntry = (HOOKFUNC)scrdecor_dispatcher;
619 return cl;