1 /**
2  * @file button.c
3  * @author Joe Wingbermuehle
4  * @date 2004-2006
5  *
6  * @brief Functions for rendering buttons.
7  *
8  */
9 
10 #include "jwm.h"
11 #include "button.h"
12 #include "border.h"
13 #include "main.h"
14 #include "icon.h"
15 #include "image.h"
16 #include "misc.h"
17 #include "settings.h"
18 
19 /** Draw a button. */
DrawButton(ButtonNode * bp)20 void DrawButton(ButtonNode *bp)
21 {
22 
23    ColorType fg;
24    long bg1, bg2;
25    long up, down;
26    DecorationsType decorations;
27 
28    Drawable drawable;
29    GC gc;
30    int x, y;
31    int width, height;
32    int xoffset, yoffset;
33 
34    int iconWidth, iconHeight;
35    int textWidth, textHeight;
36 
37    Assert(bp);
38 
39    drawable = bp->drawable;
40    x = bp->x;
41    y = bp->y;
42    width = bp->width;
43    height = bp->height;
44    gc = JXCreateGC(display, drawable, 0, NULL);
45 
46    /* Determine the colors to use. */
47    switch(bp->type) {
48    case BUTTON_LABEL:
49       fg = COLOR_MENU_FG;
50       bg1 = colors[COLOR_MENU_BG];
51       bg2 = colors[COLOR_MENU_BG];
52       up = colors[COLOR_MENU_UP];
53       down = colors[COLOR_MENU_DOWN];
54       decorations = settings.menuDecorations;
55       break;
56    case BUTTON_MENU_ACTIVE:
57       fg = COLOR_MENU_ACTIVE_FG;
58       bg1 = colors[COLOR_MENU_ACTIVE_BG1];
59       bg2 = colors[COLOR_MENU_ACTIVE_BG2];
60       down = colors[COLOR_MENU_ACTIVE_UP];
61       up = colors[COLOR_MENU_ACTIVE_DOWN];
62       decorations = settings.menuDecorations;
63       break;
64    case BUTTON_TRAY:
65       fg = COLOR_TRAYBUTTON_FG;
66       bg1 = colors[COLOR_TRAYBUTTON_BG1];
67       bg2 = colors[COLOR_TRAYBUTTON_BG2];
68       up = colors[COLOR_TRAYBUTTON_UP];
69       down = colors[COLOR_TRAYBUTTON_DOWN];
70       decorations = settings.trayDecorations;
71       break;
72    case BUTTON_TRAY_ACTIVE:
73       fg = COLOR_TRAYBUTTON_ACTIVE_FG;
74       bg1 = colors[COLOR_TRAYBUTTON_ACTIVE_BG1];
75       bg2 = colors[COLOR_TRAYBUTTON_ACTIVE_BG2];
76       down = colors[COLOR_TRAYBUTTON_ACTIVE_UP];
77       up = colors[COLOR_TRAYBUTTON_ACTIVE_DOWN];
78       decorations = settings.trayDecorations;
79       break;
80    case BUTTON_TASK:
81       fg = COLOR_TASKLIST_FG;
82       bg1 = colors[COLOR_TASKLIST_BG1];
83       bg2 = colors[COLOR_TASKLIST_BG2];
84       up = colors[COLOR_TASKLIST_UP];
85       down = colors[COLOR_TASKLIST_DOWN];
86       decorations = settings.taskListDecorations;
87       break;
88    case BUTTON_TASK_ACTIVE:
89       fg = COLOR_TASKLIST_ACTIVE_FG;
90       bg1 = colors[COLOR_TASKLIST_ACTIVE_BG1];
91       bg2 = colors[COLOR_TASKLIST_ACTIVE_BG2];
92       down = colors[COLOR_TASKLIST_ACTIVE_UP];
93       up = colors[COLOR_TASKLIST_ACTIVE_DOWN];
94       decorations = settings.taskListDecorations;
95       break;
96    case BUTTON_MENU:
97    default:
98       fg = COLOR_MENU_FG;
99       bg1 = colors[COLOR_MENU_BG];
100       bg2 = colors[COLOR_MENU_BG];
101       up = colors[COLOR_MENU_UP];
102       down = colors[COLOR_MENU_DOWN];
103       decorations = settings.menuDecorations;
104       break;
105    }
106 
107    /* Draw the background. */
108    if(bp->fill) {
109 
110       /* Draw the button background. */
111       JXSetForeground(display, gc, bg1);
112       if(bg1 == bg2) {
113          /* single color */
114          JXFillRectangle(display, drawable, gc, x, y, width, height);
115       } else {
116          /* gradient */
117          DrawHorizontalGradient(drawable, gc, bg1, bg2,
118                                 x, y, width, height);
119       }
120 
121    }
122 
123    /* Draw the border. */
124    if(bp->border) {
125       if(decorations == DECO_MOTIF) {
126          JXSetForeground(display, gc, up);
127          JXDrawLine(display, drawable, gc, x, y, x + width - 1, y);
128          JXDrawLine(display, drawable, gc, x, y, x, y + height - 1);
129          JXSetForeground(display, gc, down);
130          JXDrawLine(display, drawable, gc, x, y + height - 1,
131                     x + width - 1, y + height - 1);
132          JXDrawLine(display, drawable, gc, x + width - 1, y,
133                     x + width - 1, y + height - 1);
134       } else {
135          JXSetForeground(display, gc, down);
136          JXDrawRectangle(display, drawable, gc, x, y, width - 1, height - 1);
137       }
138    }
139 
140    /* Determine the size of the icon (if any) to display. */
141    iconWidth = 0;
142    iconHeight = 0;
143    if(bp->icon) {
144       if(bp->icon == &emptyIcon) {
145          iconWidth = Min(width - 4, height - 4);
146          iconHeight = iconWidth;
147       } else {
148          const int ratio = (bp->icon->width << 16) / bp->icon->height;
149          int maxIconWidth = width - 4;
150          if(bp->text) {
151             /* Showing text, keep the icon square. */
152             maxIconWidth = Min(width, height) - 4;
153          }
154          iconHeight = height - 4;
155          iconWidth = (iconHeight * ratio) >> 16;
156          if(iconWidth > maxIconWidth) {
157             iconWidth = maxIconWidth;
158             iconHeight = (iconWidth << 16) / ratio;
159          }
160       }
161    }
162 
163    /* Determine how much room is left for text. */
164    textWidth = 0;
165    textHeight = 0;
166    if(bp->text && (width > height || !bp->icon)) {
167       textWidth = GetStringWidth(bp->font, bp->text);
168       textHeight = GetStringHeight(bp->font);
169       if(iconWidth > 0 && textWidth + iconWidth + 7 > width) {
170          textWidth = width - iconWidth - 7;
171       } else if(iconWidth == 0 && textWidth + 5 > width) {
172          textWidth = width - 5;
173       }
174       textWidth = textWidth < 0 ? 0 : textWidth;
175    }
176 
177    /* Determine the offset of the text in the button. */
178    if(bp->alignment == ALIGN_CENTER || width <= height) {
179       xoffset = (width - iconWidth - textWidth + 1) / 2;
180       if(xoffset < 0) {
181          xoffset = 0;
182       }
183    } else {
184       xoffset = 2;
185    }
186 
187    /* Display the icon. */
188    if(bp->icon) {
189       yoffset = (height - iconHeight + 1) / 2;
190       PutIcon(bp->icon, drawable, colors[fg],
191               x + xoffset, y + yoffset,
192               iconWidth, iconHeight);
193       xoffset += iconWidth + 2;
194    }
195 
196    /* Display the label. */
197    if(textWidth > 0) {
198       yoffset = (height - textHeight + 1) / 2;
199       RenderString(drawable, bp->font, fg,
200                    x + xoffset, y + yoffset,
201                    textWidth, bp->text);
202    }
203 
204    JXFreeGC(display, gc);
205 
206 }
207 
208 /** Reset a button node with default values. */
ResetButton(ButtonNode * bp,Drawable d)209 void ResetButton(ButtonNode *bp, Drawable d)
210 {
211 
212    Assert(bp);
213 
214    bp->type = BUTTON_MENU;
215    bp->drawable = d;
216    bp->font = FONT_TRAY;
217    bp->alignment = ALIGN_LEFT;
218    bp->x = 0;
219    bp->y = 0;
220    bp->width = 1;
221    bp->height = 1;
222    bp->icon = NULL;
223    bp->text = NULL;
224    bp->fill = 1;
225    bp->border = 0;
226 
227 }
228