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