1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <ui_sb_view.h>
6
7 #include "exsb_common.h"
8 #include "next_data.h"
9
10 #define WIDTH 18
11 #define BOTTOM_MARGIN 35
12
13 #define BUTTON_SIZE 16
14 #define UP_BUTTON_Y(view_height) ((view_height)-BUTTON_SIZE * 2 - 2)
15 #define DOWN_BUTTON_Y(view_height) ((view_height)-BUTTON_SIZE - 1)
16
17 #define BAR_RELIEF_SIZE 6
18 #define BAR_RELIEF_X 5
19
20 typedef struct next_sb_view {
21 ui_sb_view_t view;
22
23 GC gc;
24
25 unsigned int depth;
26
27 Pixmap background;
28 Pixmap bar_relief;
29 Pixmap arrow_up;
30 Pixmap arrow_up_pressed;
31 Pixmap arrow_down;
32 Pixmap arrow_down_pressed;
33
34 unsigned long gray_light;
35 unsigned long gray_dark;
36
37 int has_scrollbuf;
38 int is_transparent;
39
40 } next_sb_view_t;
41
42 /* --- static functions --- */
43
get_icon_pixmap(ui_sb_view_t * view,GC gc,char ** data,unsigned int width,unsigned int height)44 static Pixmap get_icon_pixmap(ui_sb_view_t *view, GC gc, char **data, unsigned int width,
45 unsigned int height) {
46 Pixmap pix;
47 next_sb_view_t *next_sb;
48 char cur = '\0';
49 short x;
50 short y;
51 XPoint *xpoint;
52 int i = 0;
53
54 next_sb = (next_sb_view_t *)view;
55
56 pix = XCreatePixmap(view->display, view->window, width, height, next_sb->depth);
57
58 if ((xpoint = malloc((width * height) * sizeof(XPoint))) == NULL) {
59 return pix;
60 }
61
62 for (y = 0; y < height; y++) {
63 for (x = 0; x < width; x++) {
64 if (cur != data[y][x]) {
65 if (i) {
66 /* before setting gc,
67 draw stocked points */
68 XDrawPoints(view->display, pix, gc, xpoint, i, CoordModeOrigin);
69 i = 0;
70 }
71
72 /* changing gc */
73 if (data[y][x] == ' ') {
74 XSetForeground(view->display, gc, WhitePixel(view->display, view->screen));
75 } else if (data[y][x] == '#') {
76 XSetForeground(view->display, gc, BlackPixel(view->display, view->screen));
77 } else if (data[y][x] == '+') {
78 XSetForeground(view->display, gc, next_sb->gray_dark);
79 } else if (data[y][x] == '-') {
80 XSetForeground(view->display, gc, next_sb->gray_light);
81 }
82
83 cur = data[y][x];
84 }
85
86 /* stocking point */
87 xpoint[i].x = x;
88 xpoint[i].y = y;
89 i++;
90 }
91 }
92
93 if (i) {
94 XDrawPoints(view->display, pix, gc, xpoint, i, CoordModeOrigin);
95 }
96
97 free(xpoint);
98
99 return pix;
100 }
101
get_geometry_hints(ui_sb_view_t * view,unsigned int * width,unsigned int * top_margin,unsigned int * bottom_margin,int * up_button_y,unsigned int * up_button_height,int * down_button_y,unsigned int * down_button_height)102 static void get_geometry_hints(ui_sb_view_t *view, unsigned int *width, unsigned int *top_margin,
103 unsigned int *bottom_margin, int *up_button_y,
104 unsigned int *up_button_height, int *down_button_y,
105 unsigned int *down_button_height) {
106 *width = WIDTH;
107 *top_margin = 0;
108 *bottom_margin = BOTTOM_MARGIN;
109 *up_button_y = -(BUTTON_SIZE + 1) * 2;
110 *up_button_height = BUTTON_SIZE;
111 *down_button_y = -(BUTTON_SIZE + 1);
112 *down_button_height = BUTTON_SIZE;
113 }
114
get_default_color(ui_sb_view_t * view,char ** fg_color,char ** bg_color)115 static void get_default_color(ui_sb_view_t *view, char **fg_color, char **bg_color) {
116 *fg_color = "gray";
117 *bg_color = "lightgray";
118 }
119
create_bg(ui_sb_view_t * view,int width,int height)120 static Pixmap create_bg(ui_sb_view_t *view, int width, int height) {
121 Pixmap pix;
122 next_sb_view_t *next_sb;
123 short x;
124 short y;
125 XPoint *xpoint;
126 int i = 0;
127
128 next_sb = (next_sb_view_t *)view;
129
130 pix = XCreatePixmap(view->display, view->window, width, height, ((next_sb_view_t *)view)->depth);
131
132 XSetForeground(view->display, next_sb->gc, next_sb->gray_light);
133 XFillRectangle(view->display, pix, next_sb->gc, 0, 0, width, height);
134
135 if ((xpoint = malloc((width * height / 2) * sizeof(XPoint))) == NULL) {
136 return pix;
137 }
138
139 XSetForeground(view->display, next_sb->gc, next_sb->gray_dark);
140 for (y = 0; y < height; y += 2) {
141 for (x = 1; x < width - 1; x += 2) {
142 xpoint[i].x = x;
143 xpoint[i].y = y;
144 i++;
145 }
146 }
147 for (y = 1; y < height; y += 2) {
148 for (x = 2; x < width - 1; x += 2) {
149 xpoint[i].x = x;
150 xpoint[i].y = y;
151 i++;
152 }
153 }
154 XDrawPoints(view->display, pix, next_sb->gc, xpoint, i, CoordModeOrigin);
155
156 free(xpoint);
157
158 return pix;
159 }
160
realized(ui_sb_view_t * view,Display * display,int screen,Window window,GC gc,unsigned int height)161 static void realized(ui_sb_view_t *view, Display *display, int screen, Window window, GC gc,
162 unsigned int height) {
163 next_sb_view_t *next_sb;
164 XWindowAttributes attr;
165 XGCValues gc_value;
166
167 next_sb = (next_sb_view_t *)view;
168
169 view->display = display;
170 view->screen = screen;
171 view->window = window;
172 view->gc = gc;
173 view->height = height;
174
175 gc_value.foreground = BlackPixel(view->display, view->screen);
176 gc_value.background = WhitePixel(view->display, view->screen);
177 gc_value.graphics_exposures = 0;
178
179 next_sb->gc = XCreateGC(view->display, view->window,
180 GCForeground | GCBackground | GCGraphicsExposures, &gc_value);
181
182 XGetWindowAttributes(view->display, view->window, &attr);
183 next_sb->depth = attr.depth;
184
185 next_sb->gray_light =
186 exsb_get_pixel(view->display, view->screen, attr.colormap, attr.visual, "rgb:ae/aa/ae");
187 next_sb->gray_dark =
188 exsb_get_pixel(view->display, view->screen, attr.colormap, attr.visual, "rgb:51/55/51");
189
190 next_sb->background = create_bg(view, WIDTH, view->height);
191 next_sb->bar_relief =
192 get_icon_pixmap(view, next_sb->gc, bar_relief_src, BAR_RELIEF_SIZE, BAR_RELIEF_SIZE);
193 next_sb->arrow_up = get_icon_pixmap(view, next_sb->gc, arrow_up_src, BUTTON_SIZE, BUTTON_SIZE);
194 next_sb->arrow_down =
195 get_icon_pixmap(view, next_sb->gc, arrow_down_src, BUTTON_SIZE, BUTTON_SIZE);
196 next_sb->arrow_up_pressed =
197 get_icon_pixmap(view, next_sb->gc, arrow_up_pressed_src, BUTTON_SIZE, BUTTON_SIZE);
198 next_sb->arrow_down_pressed =
199 get_icon_pixmap(view, next_sb->gc, arrow_down_pressed_src, BUTTON_SIZE, BUTTON_SIZE);
200
201 XCopyArea(view->display, next_sb->background, view->window, view->gc, 0, 0, WIDTH, view->height,
202 0, 0);
203 }
204
resized(ui_sb_view_t * view,Window window,unsigned int height)205 static void resized(ui_sb_view_t *view, Window window, unsigned int height) {
206 next_sb_view_t *next_sb;
207
208 next_sb = (next_sb_view_t *)view;
209
210 view->window = window;
211 view->height = height;
212
213 /* create new background pixmap to fit well with resized scroll view */
214 XFreePixmap(view->display, next_sb->background);
215 next_sb->background = create_bg(view, WIDTH, view->height);
216 }
217
destroy(ui_sb_view_t * view)218 static void destroy(ui_sb_view_t *view) {
219 next_sb_view_t *next_sb;
220
221 next_sb = (next_sb_view_t *)view;
222
223 if (next_sb) {
224 XFreePixmap(view->display, next_sb->background);
225 XFreePixmap(view->display, next_sb->bar_relief);
226 XFreePixmap(view->display, next_sb->arrow_up);
227 XFreePixmap(view->display, next_sb->arrow_up_pressed);
228 XFreePixmap(view->display, next_sb->arrow_down);
229 XFreePixmap(view->display, next_sb->arrow_down_pressed);
230
231 XFreeGC(view->display, next_sb->gc);
232
233 free(next_sb);
234 }
235 }
236
draw_up_button(ui_sb_view_t * view,int is_pressed)237 static void draw_up_button(ui_sb_view_t *view, int is_pressed) {
238 next_sb_view_t *next_sb;
239 Pixmap arrow;
240 char **src;
241 int x;
242 int y;
243
244 next_sb = (next_sb_view_t *)view;
245
246 /* clear */
247 if (next_sb->is_transparent) {
248 XClearArea(view->display, view->window, 1, UP_BUTTON_Y(view->height), BUTTON_SIZE, BUTTON_SIZE,
249 0);
250 } else {
251 XCopyArea(view->display, next_sb->background, view->window, view->gc, 0,
252 UP_BUTTON_Y(view->height) - 1, WIDTH, BUTTON_SIZE + 2, 0,
253 UP_BUTTON_Y(view->height) - 1);
254 }
255
256 /* if no scrollback buffer, not draw */
257 if (!next_sb->has_scrollbuf) {
258 return;
259 }
260
261 if (is_pressed) {
262 arrow = next_sb->arrow_up_pressed;
263 src = arrow_up_pressed_src;
264 } else {
265 arrow = next_sb->arrow_up;
266 src = arrow_up_src;
267 }
268
269 /* drowing upper arrow button */
270 if (next_sb->is_transparent) {
271 for (y = 0; y < BUTTON_SIZE; y++) {
272 for (x = 0; x < BUTTON_SIZE; x++) {
273 if (src[y][x] == '-') {
274 XCopyArea(view->display, view->window, arrow, view->gc, x + 1,
275 y + UP_BUTTON_Y(view->height), 1, 1, x, y);
276 }
277 }
278 }
279 }
280 XCopyArea(view->display, arrow, view->window, view->gc, 0, 0, BUTTON_SIZE, BUTTON_SIZE, 1,
281 UP_BUTTON_Y(view->height));
282 }
283
draw_down_button(ui_sb_view_t * view,int is_pressed)284 static void draw_down_button(ui_sb_view_t *view, int is_pressed) {
285 next_sb_view_t *next_sb;
286 Pixmap arrow;
287 char **src;
288 int x;
289 int y;
290
291 next_sb = (next_sb_view_t *)view;
292
293 /* clear */
294 if (next_sb->is_transparent) {
295 XClearArea(view->display, view->window, 1, DOWN_BUTTON_Y(view->height), BUTTON_SIZE,
296 BUTTON_SIZE, 0);
297 } else {
298 XCopyArea(view->display, next_sb->background, view->window, view->gc, 0,
299 DOWN_BUTTON_Y(view->height), WIDTH, BUTTON_SIZE + 1, 0, DOWN_BUTTON_Y(view->height));
300 }
301
302 /* if no scrollback buffer, not draw */
303 if (!next_sb->has_scrollbuf) {
304 return;
305 }
306
307 if (is_pressed) {
308 arrow = next_sb->arrow_down_pressed;
309 src = arrow_down_pressed_src;
310 } else {
311 arrow = next_sb->arrow_down;
312 src = arrow_down_src;
313 }
314
315 /* drowing down arrow button */
316 if (next_sb->is_transparent) {
317 for (y = 0; y < BUTTON_SIZE; y++) {
318 for (x = 0; x < BUTTON_SIZE; x++) {
319 if (src[y][x] == '-') {
320 XCopyArea(view->display, view->window, arrow, view->gc, x + 1,
321 y + DOWN_BUTTON_Y(view->height), 1, 1, x, y);
322 }
323 }
324 }
325 }
326 XCopyArea(view->display, arrow, view->window, view->gc, 0, 0, BUTTON_SIZE, BUTTON_SIZE, 1,
327 DOWN_BUTTON_Y(view->height));
328 }
329
draw_scrollbar(ui_sb_view_t * view,int bar_top_y,unsigned int bar_height)330 static void draw_scrollbar(ui_sb_view_t *view, int bar_top_y, unsigned int bar_height) {
331 next_sb_view_t *next_sb;
332 XSegment line[2];
333
334 next_sb = (next_sb_view_t *)view;
335
336 if (bar_top_y == 0 && bar_height == view->height - BOTTOM_MARGIN) {
337 /* drawing scroll view background to clear */
338 /* FIXME: should use XSetWindowBackgroundPixmap() */
339 if (!next_sb->is_transparent) {
340 XCopyArea(view->display, next_sb->background, view->window, view->gc, 0, 0, WIDTH,
341 view->height - BOTTOM_MARGIN, 0, 0);
342 } else {
343 XClearArea(view->display, view->window, 1, 0, WIDTH - 2, view->height - BOTTOM_MARGIN, 0);
344 }
345 return; /* if no scrollback buffer, not draw bar */
346 }
347
348 /* rise up/down button */
349 if (next_sb->has_scrollbuf == 0) {
350 next_sb->has_scrollbuf = 1;
351 draw_up_button(view, 0);
352 draw_down_button(view, 0);
353 }
354
355 /* clear */
356 if (next_sb->is_transparent) {
357 XClearArea(view->display, view->window, 1, 0, WIDTH - 2, view->height - BOTTOM_MARGIN, 0);
358 } else {
359 /* FIXME: should use XSetWindowBackgroundPixmap() */
360 XCopyArea(view->display, next_sb->background, view->window, view->gc, 0, 0, WIDTH, bar_top_y, 0,
361 0);
362 XCopyArea(view->display, next_sb->background, view->window, view->gc, 0, bar_top_y, WIDTH,
363 view->height - bar_top_y - bar_height - BOTTOM_MARGIN, 0, bar_top_y + bar_height);
364 XSetForeground(view->display, next_sb->gc, next_sb->gray_light);
365 line[0].x1 = 0;
366 line[0].y1 = bar_top_y;
367 line[0].x2 = 0;
368 line[0].y2 = bar_top_y + view->height - 1;
369 line[1].x1 = WIDTH - 1;
370 line[1].y1 = bar_top_y;
371 line[1].x2 = WIDTH - 1;
372 line[1].y2 = bar_top_y + bar_height - 1;
373 XDrawSegments(view->display, view->window, next_sb->gc, line, 2);
374 }
375
376 /* drawing bar */
377 if (!next_sb->is_transparent) {
378 XSetForeground(view->display, next_sb->gc, next_sb->gray_light);
379 XFillRectangle(view->display, view->window, next_sb->gc, 1, bar_top_y, WIDTH - 2, bar_height);
380 }
381
382 /* drawing relief */
383 if (bar_height >= BAR_RELIEF_SIZE) {
384 XCopyArea(view->display, next_sb->bar_relief, view->window, next_sb->gc, 1, 0,
385 BAR_RELIEF_SIZE - 2, 1, BAR_RELIEF_X + 1,
386 bar_top_y + (bar_height - BAR_RELIEF_SIZE) / 2);
387 XCopyArea(view->display, next_sb->bar_relief, view->window, next_sb->gc, 0, 1, BAR_RELIEF_SIZE,
388 BAR_RELIEF_SIZE - 2, BAR_RELIEF_X,
389 bar_top_y + (bar_height - BAR_RELIEF_SIZE) / 2 + 1);
390 XCopyArea(view->display, next_sb->bar_relief, view->window, next_sb->gc, 1, 5,
391 BAR_RELIEF_SIZE - 2, 1, BAR_RELIEF_X + 1,
392 bar_top_y + (bar_height - BAR_RELIEF_SIZE) / 2 + 5);
393 #if 0
394 XCopyArea(view->display, next_sb->bar_relief, view->window, next_sb->gc, 0, 0, BAR_RELIEF_SIZE,
395 BAR_RELIEF_SIZE, BAR_RELIEF_X, bar_top_y + (bar_height - BAR_RELIEF_SIZE) / 2);
396 #endif
397 }
398
399 /* bar's highlight */
400 XSetForeground(view->display, next_sb->gc, WhitePixel(view->display, view->screen));
401 line[0].x1 = 1;
402 line[0].y1 = bar_top_y;
403 line[0].x2 = 1;
404 line[0].y2 = bar_top_y + bar_height - 1;
405 line[1].x1 = 2;
406 line[1].y1 = bar_top_y;
407 line[1].x2 = WIDTH - 3;
408 line[1].y2 = bar_top_y;
409 XDrawSegments(view->display, view->window, next_sb->gc, line, 2);
410
411 /* bar's shade (black) */
412 XSetForeground(view->display, next_sb->gc, BlackPixel(view->display, view->screen));
413 line[0].x1 = WIDTH - 2;
414 line[0].y1 = bar_top_y;
415 line[0].x2 = WIDTH - 2;
416 line[0].y2 = bar_top_y + bar_height - 1;
417 line[1].x1 = 1;
418 line[1].y1 = bar_top_y + bar_height - 1;
419 line[1].x2 = WIDTH - 3;
420 line[1].y2 = bar_top_y + bar_height - 1;
421 XDrawSegments(view->display, view->window, next_sb->gc, line, 2);
422
423 /* bar's shade (nextish dark gray) */
424 XSetForeground(view->display, next_sb->gc, next_sb->gray_dark);
425 line[0].x1 = WIDTH - 3;
426 line[0].y1 = bar_top_y + 1;
427 line[0].x2 = WIDTH - 3;
428 line[0].y2 = bar_top_y + bar_height - 2;
429 line[1].x1 = 2;
430 line[1].y1 = bar_top_y + bar_height - 2;
431 line[1].x2 = WIDTH - 4;
432 line[1].y2 = bar_top_y + bar_height - 2;
433 XDrawSegments(view->display, view->window, next_sb->gc, line, 2);
434 }
435
436 /* --- global functions --- */
437
ui_next_sb_view_new(void)438 ui_sb_view_t *ui_next_sb_view_new(void) {
439 next_sb_view_t *next_sb;
440
441 if ((next_sb = calloc(1, sizeof(next_sb_view_t))) == NULL) {
442 return NULL;
443 }
444
445 next_sb->view.version = 1;
446
447 next_sb->view.get_geometry_hints = get_geometry_hints;
448 next_sb->view.get_default_color = get_default_color;
449 next_sb->view.realized = realized;
450 next_sb->view.resized = resized;
451 next_sb->view.destroy = destroy;
452
453 next_sb->view.draw_scrollbar = draw_scrollbar;
454
455 next_sb->view.draw_up_button = draw_up_button;
456 next_sb->view.draw_down_button = draw_down_button;
457
458 return (ui_sb_view_t *)next_sb;
459 }
460
ui_next_transparent_sb_view_new(void)461 ui_sb_view_t *ui_next_transparent_sb_view_new(void) {
462 next_sb_view_t *next_sb;
463
464 if ((next_sb = calloc(1, sizeof(next_sb_view_t))) == NULL) {
465 return NULL;
466 }
467
468 next_sb->view.version = 1;
469
470 next_sb->view.get_geometry_hints = get_geometry_hints;
471 next_sb->view.get_default_color = get_default_color;
472 next_sb->view.realized = realized;
473 next_sb->view.resized = resized;
474 next_sb->view.destroy = destroy;
475
476 next_sb->view.draw_scrollbar = draw_scrollbar;
477
478 next_sb->view.draw_up_button = draw_up_button;
479 next_sb->view.draw_down_button = draw_down_button;
480
481 next_sb->is_transparent = 1;
482
483 return (ui_sb_view_t *)next_sb;
484 }
485