Fixed out-by-one error in previous commit.
[AROS.git] / workbench / c / Decoration / screendecorclass.c
blob020b2110bc35519967e90e6b501028a0fbc44f71
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 Screen *scr, LONG *left, LONG *right)
125 struct Gadget *g;
127 *left = 0;
128 *right = scr->Width - 1;
130 for (g = scr->FirstGadget; g; g = g->NextGadget)
132 if (!(g->Flags & GFLG_RELRIGHT))
134 if (g->LeftEdge + g->Width > *left) *left = g->LeftEdge + g->Width;
136 else
138 if (g->LeftEdge + scr->Width - 1 - 1 < *right) *right = g->LeftEdge + scr->Width - 1 - 1;
143 static IPTR scrdecor_set(Class *cl, Object *obj, struct opSet *msg)
145 struct scrdecor_data *data = INST_DATA(cl, obj);
146 struct TagItem *tags = msg->ops_AttrList;
147 struct TagItem *tstate;
148 struct TagItem *tag;
150 tstate = tags;
151 while ((tag = NextTagItem(&tstate)))
153 switch (tag->ti_Tag)
155 case SDA_TitleChild:
156 if (tag->ti_Data)
158 if (!(data->FirstChild))
160 LONG left, right = 0;
161 struct GadgetInfo childgadinf;
162 struct gpLayout childlayoutmsg;
163 D(bug("[screendecor] SDA_TitleChild: 0x%p\n", tag->ti_Data));
165 if ((childgadinf.gi_Screen = LockPubScreen(NULL)) != NULL)
167 UnlockPubScreen(NULL, childgadinf.gi_Screen);
168 data->FirstChild = (Object *)tag->ti_Data;
169 ((struct Gadget *)(data->FirstChild))->SpecialInfo = childgadinf.gi_Screen;
171 childgadinf.gi_RastPort = childgadinf.gi_Screen->BarLayer->rp;
173 if ((childgadinf.gi_DrInfo = GetScreenDrawInfo(childgadinf.gi_Screen)) != NULL)
175 childgadinf.gi_Pens.DetailPen = childgadinf.gi_DrInfo->dri_Pens[DETAILPEN];
176 childgadinf.gi_Pens.BlockPen = childgadinf.gi_DrInfo->dri_Pens[BLOCKPEN];
179 childlayoutmsg.MethodID = GM_LAYOUT;
180 childlayoutmsg.gpl_GInfo = &childgadinf;
181 childlayoutmsg.gpl_Initial = 0;
183 ((struct Gadget *)(data->FirstChild))->TopEdge = 0 + CHILDPADDING;
184 ((struct Gadget *)(data->FirstChild))->Height = childgadinf.gi_Screen->BarHeight - (CHILDPADDING << 1);
186 DoMethodA(data->FirstChild, &childlayoutmsg);
188 scr_findtitlearea((childgadinf.gi_Screen), &left, &right);
190 ((struct Gadget *)(data->FirstChild))->LeftEdge = right - ((struct Gadget *)(data->FirstChild))->Width + 1;
192 childlayoutmsg.MethodID = GM_GOACTIVE;
193 DoMethodA(data->FirstChild, &childlayoutmsg);
197 break;
198 default:
199 return DoSuperMethodA(cl, obj, (Msg)msg);
202 return 1;
205 static IPTR scrdecor_draw_screenbar(Class *cl, Object *obj, struct sdpDrawScreenBar *msg)
207 struct scrdecor_data *data = INST_DATA(cl, obj);
208 struct ScreenData *sd = (struct ScreenData *) msg->sdp_UserBuffer;
209 struct TextExtent te;
210 struct RastPort *rp = msg->sdp_RPort;
211 struct Screen *scr = msg->sdp_Screen;
212 struct DrawInfo *dri = msg->sdp_Dri;
213 UWORD *pens = dri->dri_Pens;
214 LONG left, right = 0, titlelen = 0;
215 BOOL hastitle = TRUE;
216 BOOL beeping = scr->Flags & BEEPING;
218 if (beeping) {
219 SetAPen(rp, pens[BARDETAILPEN]);
220 RectFill(rp, 0, 0, scr->Width, sd->img_stitlebar->h);
221 } else {
222 if (sd->img_stitlebar->ok)
223 WriteVerticalScaledTiledImageHorizontal(rp, sd->img_stitlebar, 0, 0,
224 sd->img_stitlebar->w, 0, 0, data->dc->SBarHeight, scr->Width, scr->BarHeight + 1);
226 if (sd->img_sbarlogo->ok)
227 WriteTiledImageHorizontal(rp, sd->img_sbarlogo, 0, 0,
228 sd->img_sbarlogo->w, data->dc->SLogoOffset,
229 (scr->BarHeight + 1 - sd->img_sbarlogo->h) / 2, sd->img_sbarlogo->w);
231 if (scr->Title == NULL)
232 hastitle = FALSE;
234 if (hastitle)
236 scr_findtitlearea(scr, &left, &right);
237 titlelen = strlen(scr->Title);
238 if (data->FirstChild)
240 if (((struct Gadget *)(data->FirstChild))->Width > 2) {
241 D(bug("[screendecor] draw_screenbar: titlechild width = %d\n", ((struct Gadget *)(data->FirstChild))->Width));
242 right = right - ((struct Gadget *)(data->FirstChild))->Width + 1;
245 titlelen = TextFit(rp, scr->Title, titlelen, &te, NULL, 1, right - data->dc->STitleOffset, scr->BarHeight);
246 if (titlelen == 0) hastitle = 0;
249 if (hastitle)
251 UWORD tx = data->dc->STitleOffset;
252 UWORD tymax = scr->BarHeight - (dri->dri_Font->tf_YSize - dri->dri_Font->tf_Baseline) - 1;
253 UWORD ty = ((scr->BarHeight + dri->dri_Font->tf_Baseline - 1) >> 1);
254 if (ty > tymax) ty = tymax;
256 SetFont(rp, msg->sdp_Dri->dri_Font);
257 SetDrMd(rp, JAM1);
259 if (!sd->truecolor || ((data->dc->STitleOutline == FALSE) && (data->dc->STitleShadow == FALSE)))
261 SetAPen(rp, pens[beeping ? BARBLOCKPEN : BARDETAILPEN]);
262 Move(rp, tx, ty);
263 Text(rp, scr->Title, titlelen);
265 else if (data->dc->STitleOutline)
267 SetSoftStyle(rp, FSF_BOLD, AskSoftStyle(rp));
268 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorShadow, TAG_DONE);
270 Move(rp, tx + 1, ty ); Text(rp, scr->Title, titlelen);
271 Move(rp, tx + 2, ty ); Text(rp, scr->Title, titlelen);
272 Move(rp, tx , ty ); Text(rp, scr->Title, titlelen);
273 Move(rp, tx, ty + 1); Text(rp, scr->Title, titlelen);
274 Move(rp, tx, ty + 2); Text(rp, scr->Title, titlelen);
275 Move(rp, tx + 1, ty + 2); Text(rp, scr->Title, titlelen);
276 Move(rp, tx + 2, ty + 1); Text(rp, scr->Title, titlelen);
277 Move(rp, tx + 2, ty + 2); Text(rp, scr->Title, titlelen);
279 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorText, TAG_DONE);
280 Move(rp, tx + 1, ty + 1);
281 Text(rp, scr->Title, titlelen);
282 SetSoftStyle(rp, FS_NORMAL, AskSoftStyle(rp));
284 else
286 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorShadow, TAG_DONE);
287 Move(rp, tx + 1, ty + 1 );
288 Text(rp, scr->Title, titlelen);
290 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, data->dc->STitleColorText, TAG_DONE);
291 Move(rp, tx, ty);
292 Text(rp, scr->Title, titlelen);
296 if (data->FirstChild && (((struct Gadget *)(data->FirstChild))->Width > 0)) {
297 struct GadgetInfo childgadinf;
298 struct gpRender childrendermsg =
300 GM_RENDER,
301 &childgadinf,
303 GREDRAW_REDRAW
306 childgadinf.gi_Screen = ((struct Gadget *)(data->FirstChild))->SpecialInfo = scr;
307 childgadinf.gi_RastPort = rp;
308 childgadinf.gi_Pens.DetailPen = pens[DETAILPEN];
309 childgadinf.gi_Pens.BlockPen = pens[BLOCKPEN];
310 childgadinf.gi_DrInfo = dri;
311 childgadinf.gi_Domain.Left = right;
312 childgadinf.gi_Domain.Top = 0 + CHILDPADDING;
313 childgadinf.gi_Domain.Width = ((struct Gadget *)(data->FirstChild))->Width;
314 childgadinf.gi_Domain.Height = sd->img_stitlebar->h - (CHILDPADDING << 1);
315 D(bug("[screendecor] draw_screenbar: rendering titlechild @ 0x%p, msg @ 0x%p, info @ 0x%p\n", data->FirstChild, &childrendermsg, &childgadinf));
316 DoMethodA(data->FirstChild, &childrendermsg);
319 return TRUE;
322 static IPTR scrdecor_getdefsize_sysimage(Class *cl, Object *obj, struct sdpGetDefSizeSysImage *msg)
324 struct scrdecor_data *data = INST_DATA(cl, obj);
326 if (msg->sdp_Which == SDEPTHIMAGE)
328 if (data->di && data->di->img_sdepth)
330 *msg->sdp_Height = data->di->img_sdepth->h;
331 *msg->sdp_Width = data->di->img_sdepth->w >> 1;
333 else return DoSuperMethodA(cl, obj, (Msg) msg);
335 else return DoSuperMethodA(cl, obj, (Msg) msg);
337 return TRUE;
340 static IPTR scrdecor_draw_sysimage(Class *cl, Object *obj, struct sdpDrawSysImage *msg)
342 struct ScreenData *sd = (struct ScreenData *) msg->sdp_UserBuffer;
344 struct RastPort *rp = msg->sdp_RPort;
345 LONG left = msg->sdp_X;
346 LONG top = msg->sdp_Y;
347 LONG width = msg->sdp_Width;
348 LONG height = msg->sdp_Height;
349 LONG state = msg->sdp_State;
351 if (msg->sdp_Which == SDEPTHIMAGE)
353 if (&sd->img_sdepth)
355 DrawScaledStatefulGadgetImageToRP(rp, sd->img_sdepth, state, left, top, width, height);
357 else return DoSuperMethodA(cl, obj, (Msg) msg);
359 else return DoSuperMethodA(cl, obj, (Msg) msg);
361 return TRUE;
364 static IPTR scrdecor_layoutscrgadgets(Class *cl, Object *obj, struct sdpLayoutScreenGadgets *msg)
366 struct Gadget *gadget = msg->sdp_Gadgets;
367 struct ScreenData *sd = (struct ScreenData *) msg->sdp_UserBuffer;
369 struct scrdecor_data *data = INST_DATA(cl, obj);
371 while(gadget)
373 switch(gadget->GadgetType & GTYP_SYSTYPEMASK)
375 case GTYP_SDEPTH:
376 gadget->LeftEdge = -gadget->Width + 1;
377 gadget->TopEdge = (data->dc->SBarHeight - sd->img_sdepth->h) >> 1;
378 gadget->Flags &= ~GFLG_RELWIDTH;
379 gadget->Flags |= GFLG_RELRIGHT;
380 break;
383 if (msg->sdp_Flags & SDF_LSG_MULTIPLE)
385 gadget = gadget->NextGadget;
387 else
389 gadget = NULL;
393 return TRUE;
396 static IPTR scrdecor_initscreen(Class *cl, Object *obj, struct sdpInitScreen *msg)
398 struct scrdecor_data *data = INST_DATA(cl, obj);
399 struct ScreenData *sd = (struct ScreenData *)msg->sdp_UserBuffer;
400 struct Screen *screen = msg->sdp_Screen;
402 sd->truecolor = msg->sdp_TrueColor;
404 BOOL truecolor = sd->truecolor;
407 * This depends on openwindow.c adding font height to w->BorderTop.
408 * It allows the window title bar to grow when font is bigger than decoration defined height
410 if ((msg->sdp_FontHeight + 2) > data->dc->BarHeight)
411 msg->sdp_WBorTop = 1;
412 else
413 msg->sdp_WBorTop = data->dc->BarHeight - 1 - msg->sdp_FontHeight;
415 /* Allow scaling title bar above decoration defined height */
416 msg->sdp_BarHeight = msg->sdp_FontHeight > (data->dc->SBarHeight - 1) ? msg->sdp_FontHeight : (data->dc->SBarHeight - 1);
418 msg->sdp_BarHBorder = 1;
419 msg->sdp_WBorLeft = data->dc->LeftBorder;
420 msg->sdp_WBorRight = data->dc->RightBorder;
421 msg->sdp_WBorBottom = data->dc->BottomBorder;
423 sd->ActivePen = -1;
424 sd->DeactivePen = -1;
425 #if 0 // Omitting this gives better colours on low-color screens
426 if (!truecolor) {
427 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);
428 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);
430 #endif
432 /* Convert initial images to current screen */
433 /* Make sure a structure is always generated even if there is no image
434 That was the assumption of previous code :/ */
436 sd->di = NewImages();
438 SETIMAGE_SCR(sdepth);
439 SETIMAGE_SCR(sbarlogo);
440 SETIMAGE_SCR(stitlebar);
442 SETIMAGE_SCR(size);
443 SETIMAGE_SCR(close);
444 SETIMAGE_SCR(depth);
445 SETIMAGE_SCR(zoom);
446 SETIMAGE_SCR(up);
447 SETIMAGE_SCR(down);
448 SETIMAGE_SCR(left);
449 SETIMAGE_SCR(right);
450 SETIMAGE_SCR(mui);
451 SETIMAGE_SCR(popup);
452 SETIMAGE_SCR(snapshot);
453 SETIMAGE_SCR(iconify);
454 SETIMAGE_SCR(lock);
455 SETIMAGE_SCR(winbar_normal);
456 SETIMAGE_SCR(border_normal);
457 SETIMAGE_SCR(border_deactivated);
458 SETIMAGE_SCR(verticalcontainer);
459 SETIMAGE_SCR(verticalknob);
460 SETIMAGE_SCR(horizontalcontainer);
461 SETIMAGE_SCR(horizontalknob);
463 SETIMAGE_SCR(menu);
464 SETIMAGE_SCR(amigakey);
465 SETIMAGE_SCR(menucheck);
466 SETIMAGE_SCR(submenu);
468 /* Set pointers to converted images */
469 sd->img_sdepth = sd->di->img_sdepth;
470 sd->img_sbarlogo = sd->di->img_sbarlogo;
471 sd->img_stitlebar = sd->di->img_stitlebar;
473 sd->img_amigakey = sd->di->img_amigakey;
474 sd->img_menucheck = sd->di->img_menucheck;
475 sd->img_submenu = sd->di->img_submenu;
477 return TRUE;
480 static IPTR scrdecor_exitscreen(Class *cl, Object *obj, struct sdpExitScreen *msg)
482 struct ScreenData *sd = (struct ScreenData *)msg->sdp_UserBuffer;
484 FreeImages(sd->di);
486 return TRUE;
489 /**************************************************************************************************/
491 static IPTR scrdecor_dispatcher(struct IClass *cl, Object *obj, Msg msg)
493 IPTR retval;
495 switch(msg->MethodID)
497 case OM_NEW:
498 retval = scrdecor_new(cl, obj, (struct opSet *)msg);
499 break;
501 case OM_DISPOSE:
502 retval = scrdecor_dispose(cl, obj, (struct opSet *)msg);
503 break;
505 case OM_GET:
506 retval = scrdecor_get(cl, obj, (struct opGet *)msg);
507 break;
509 case OM_SET:
510 retval = scrdecor_set(cl, obj, (struct opSet *)msg);
511 break;
513 case SDM_GETDEFSIZE_SYSIMAGE:
514 retval = scrdecor_getdefsize_sysimage(cl, obj, (struct sdpGetDefSizeSysImage *)msg);
515 break;
517 case SDM_DRAW_SCREENBAR:
518 retval = scrdecor_draw_screenbar(cl, obj, (struct sdpDrawScreenBar *)msg);
519 break;
521 case SDM_DRAW_SYSIMAGE:
522 retval = scrdecor_draw_sysimage(cl, obj, (struct sdpDrawSysImage *)msg);
523 break;
525 case SDM_LAYOUT_SCREENGADGETS:
526 retval = scrdecor_layoutscrgadgets(cl, obj, (struct sdpLayoutScreenGadgets *)msg);
527 break;
529 case SDM_INITSCREEN:
530 retval = scrdecor_initscreen(cl, obj, (struct sdpInitScreen *)msg);
531 break;
533 case SDM_EXITSCREEN:
534 retval = scrdecor_exitscreen(cl, obj, (struct sdpExitScreen *)msg);
535 break;
537 default:
538 retval = DoSuperMethodA(cl, obj, msg);
539 break;
542 return retval;
545 struct IClass * MakeScreenDecorClass()
547 struct IClass * cl = MakeClass(NULL, SCRDECORCLASS, NULL, sizeof(struct scrdecor_data), 0);
548 if (cl)
550 cl->cl_Dispatcher.h_Entry = HookEntry;
551 cl->cl_Dispatcher.h_SubEntry = (HOOKFUNC)scrdecor_dispatcher;
554 return cl;