シンプル化
This commit is contained in:
15
Makefile
15
Makefile
@@ -16,13 +16,16 @@ PREFIX = /usr/local
|
||||
|
||||
# cc | clang | gcc
|
||||
CC = cc
|
||||
IMPLEMENTS = -DSUWAUI_IMPLEMENTS_SUWAWINDOW \
|
||||
-DSUWAUI_IMPLEMENTS_SUWALABEL \
|
||||
-DSUWAUI_IMPLEMENTS_SUWABUTTON
|
||||
# lldb | gdb
|
||||
DEBUGGER = lldb
|
||||
FILES = main.c src/*.c
|
||||
FILES = *.c
|
||||
|
||||
CFLAGS = -Wall -Wextra \
|
||||
-I./dep/include -I/usr/include -I/usr/local/include -I/usr/X11R6/include \
|
||||
-L./dep/lib/${OS} -L/usr/lib -L/usr/local/lib -L/usr/X11R6/lib \
|
||||
-I./include -I/usr/include -I/usr/local/include -I/usr/X11R6/include \
|
||||
-L/usr/lib -L/usr/local/lib -L/usr/X11R6/lib \
|
||||
-I/usr/X11R6/include/freetype2 -I/usr/local/include/freetype2
|
||||
|
||||
LDFLAGS = -lc -lX11 -lXft
|
||||
@@ -39,15 +42,15 @@ SLIB += -lxcb -lpthread -lfontconfig -lz -lexpat -lfreetype -lXrender -lXau -lXd
|
||||
all: debug
|
||||
|
||||
debug:
|
||||
${CC} -O0 -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS}
|
||||
${CC} ${IMPLEMENTS} -O0 -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS}
|
||||
${DEBUGGER} -o run ${NAME}
|
||||
|
||||
develop:
|
||||
${CC} -O3 -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} ${SLIB}
|
||||
${CC} ${IMPLEMENTS} -O3 -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} ${SLIB}
|
||||
./${NAME}
|
||||
|
||||
release:
|
||||
${CC} -O3 ${CFLAGS} -o ${NAME} ${FILES} -static ${LDFLAGS} ${SLIB}
|
||||
${CC} ${IMPLEMENTS} -O3 ${CFLAGS} -o ${NAME} ${FILES} -static ${LDFLAGS} ${SLIB}
|
||||
strip ${NAME}
|
||||
./${NAME}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "display.h"
|
||||
|
||||
#define NUM_ROWS 6
|
||||
#define NUM_COLS 4
|
||||
@@ -18,8 +17,6 @@
|
||||
|
||||
char curinput[64] = {0};
|
||||
int input_pos = 0;
|
||||
int initialized = 0;
|
||||
XftColor buttonColor;
|
||||
|
||||
static const char *btn_labels[][10] = {
|
||||
{ NULL }, // 数字表示
|
||||
@@ -30,18 +27,10 @@ static const char *btn_labels[][10] = {
|
||||
{ "0", ".", "=", "<" },
|
||||
};
|
||||
|
||||
static inline float get_scale(UiSystem *ui) {
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(ui->display, ui->xwindow, &attr);
|
||||
float sx = (float)attr.width / DESIGN_WIDTH;
|
||||
float sy = (float)attr.height / DESIGN_HEIGHT;
|
||||
return sx < sy ? sx : sy;
|
||||
}
|
||||
|
||||
static SuwaButton *find_button_at(UiSystem *ui, int mx, int my) {
|
||||
static SuwaButton *find_button_at(SuwaWindow *window, int mx, int my) {
|
||||
static SuwaButton found = {0};
|
||||
|
||||
float scale = get_scale(ui);
|
||||
float scale = get_scale(window);
|
||||
if (scale <= 0) scale = 1.0f;
|
||||
|
||||
int btn_w = (int)(DESIGN_BUTTON_WIDTH * scale + .5f);
|
||||
@@ -82,29 +71,29 @@ static SuwaButton *find_button_at(UiSystem *ui, int mx, int my) {
|
||||
return &found;
|
||||
}
|
||||
|
||||
void append_to_input(UiSystem *ui, char c) {
|
||||
void append_to_input(CtrlLabels *labels, char c) {
|
||||
if ((unsigned long)input_pos >= sizeof(curinput) - 2) return;
|
||||
strcpy(ui->problemLabel.text, "");
|
||||
strcpy(labels->problem->text, "");
|
||||
curinput[input_pos++] = c;
|
||||
curinput[input_pos] = '\0';
|
||||
|
||||
strncpy(ui->resLabel.text, curinput, sizeof(ui->resLabel.text) - 1);
|
||||
ui->resLabel.text[sizeof(ui->resLabel.text) - 1] = '\0';
|
||||
strncpy(labels->res->text, curinput, sizeof(labels->res->text) - 1);
|
||||
labels->res->text[sizeof(labels->res->text) - 1] = '\0';
|
||||
}
|
||||
|
||||
void clear_calculator(UiSystem *ui) {
|
||||
strcpy(ui->problemLabel.text, "");
|
||||
void clear_calculator(CtrlLabels *labels) {
|
||||
strcpy(labels->problem->text, "");
|
||||
curinput[0] = '\0';
|
||||
input_pos = 0;
|
||||
strcpy(ui->resLabel.text, "0");
|
||||
strcpy(labels->res->text, "0");
|
||||
}
|
||||
|
||||
double evaluate_simple(UiSystem *ui, const char *expr) {
|
||||
double evaluate_simple(CtrlLabels *labels, const char *expr) {
|
||||
double res = 0.0;
|
||||
double cur = 0.0;
|
||||
char op = '+';
|
||||
int i = 0;
|
||||
snprintf(ui->problemLabel.text, sizeof(ui->problemLabel.text), "%s=", expr);
|
||||
snprintf(labels->problem->text, sizeof(labels->problem->text), "%s=", expr);
|
||||
|
||||
while (expr[i]) {
|
||||
if (expr[i] == ' ') { i++; continue; }
|
||||
@@ -144,35 +133,35 @@ double evaluate_simple(UiSystem *ui, const char *expr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
void control_expose(UiSystem *ui, XEvent *e) {
|
||||
if (e->type != Expose && e->type != ConfigureNotify) return;
|
||||
void control_expose(SuwaWindow *window, CtrlLabels *labels) {
|
||||
if (window->event.type != Expose && window->event.type != ConfigureNotify) return;
|
||||
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(ui->display, ui->xwindow, &attr);
|
||||
XGetWindowAttributes(window->display, window->xwindow, &attr);
|
||||
int w = attr.width;
|
||||
int h = attr.height;
|
||||
|
||||
if (ui->backbuf != None) XFreePixmap(ui->display, ui->backbuf);
|
||||
ui->backbuf = XCreatePixmap(ui->display, ui->xwindow, w, h,
|
||||
DefaultDepth(ui->display, DefaultScreen(ui->display)));
|
||||
if (window->backbuf != None) XFreePixmap(window->display, window->backbuf);
|
||||
window->backbuf = XCreatePixmap(window->display, window->xwindow, w, h,
|
||||
DefaultDepth(window->display, DefaultScreen(window->display)));
|
||||
|
||||
if (ui->backbuf == None) ui->backbuf = ui->xwindow;
|
||||
ui->target = ui->backbuf;
|
||||
if (window->backbuf == None) window->backbuf = window->xwindow;
|
||||
window->target = window->backbuf;
|
||||
|
||||
XftDraw *backdraw = XftDrawCreate(ui->display, ui->backbuf,
|
||||
DefaultVisual(ui->display, DefaultScreen(ui->display)),
|
||||
DefaultColormap(ui->display, DefaultScreen(ui->display)));
|
||||
XftDraw *backdraw = XftDrawCreate(window->display, window->backbuf,
|
||||
DefaultVisual(window->display, DefaultScreen(window->display)),
|
||||
DefaultColormap(window->display, DefaultScreen(window->display)));
|
||||
if (!backdraw) {
|
||||
fprintf(stderr, "Pixmap向けXftDrawの作成に失敗。\n");
|
||||
XFreePixmap(ui->display, ui->backbuf);
|
||||
ui->backbuf = None;
|
||||
XFreePixmap(window->display, window->backbuf);
|
||||
window->backbuf = None;
|
||||
return;
|
||||
}
|
||||
|
||||
XSetForeground(ui->display, ui->gc, BGCOL);
|
||||
XFillRectangle(ui->display, ui->backbuf, ui->gc, 0, 0, w, h);
|
||||
XSetForeground(window->display, window->gc, BGCOL);
|
||||
XFillRectangle(window->display, window->backbuf, window->gc, 0, 0, w, h);
|
||||
|
||||
float scale = get_scale(ui);
|
||||
float scale = get_scale(window);
|
||||
if (scale <= 0) scale = 1.f;
|
||||
|
||||
int label_padding = (int)(20 * scale + .5f);
|
||||
@@ -180,143 +169,132 @@ void control_expose(UiSystem *ui, XEvent *e) {
|
||||
// 出力
|
||||
{
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(ui->display, ui->resLabel.font,
|
||||
(const FcChar8 *)ui->resLabel.text,
|
||||
strlen(ui->resLabel.text), &extents);
|
||||
XftTextExtentsUtf8(window->display, labels->res->font,
|
||||
(const FcChar8 *)labels->res->text,
|
||||
strlen(labels->res->text), &extents);
|
||||
|
||||
int tx = w - label_padding - extents.xOff;
|
||||
int ty = (int)(180 * scale + .5f);
|
||||
|
||||
XftDrawStringUtf8(
|
||||
backdraw, &ui->resLabel.fg_color, ui->resLabel.font,
|
||||
tx, ty, (const FcChar8 *)ui->resLabel.text, 64);
|
||||
backdraw, &labels->res->fg_color, labels->res->font,
|
||||
tx, ty, (const FcChar8 *)labels->res->text, 64);
|
||||
}
|
||||
|
||||
{
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(ui->display, ui->problemLabel.font,
|
||||
(const FcChar8 *)ui->problemLabel.text,
|
||||
strlen(ui->problemLabel.text), &extents);
|
||||
XftTextExtentsUtf8(window->display, labels->problem->font,
|
||||
(const FcChar8 *)labels->problem->text,
|
||||
strlen(labels->problem->text), &extents);
|
||||
|
||||
int tx = w - label_padding - extents.xOff;
|
||||
int ty = (int)(80 * scale + .5f);
|
||||
|
||||
XftDrawStringUtf8(
|
||||
backdraw, &ui->problemLabel.fg_color, ui->problemLabel.font,
|
||||
tx, ty, (const FcChar8 *)ui->problemLabel.text, 64);
|
||||
backdraw, &labels->problem->fg_color, labels->problem->font,
|
||||
tx, ty, (const FcChar8 *)labels->problem->text, 64);
|
||||
}
|
||||
|
||||
int width = (int)(DESIGN_BUTTON_WIDTH * scale + .5f);
|
||||
int height = (int)(DESIGN_BUTTON_HEIGHT * scale + .5f);
|
||||
int padding = (int)(DESIGN_PADDING * scale + .5f);
|
||||
int start_y = (int)(DESIGN_BUTTON_AREA_Y * scale + .5f);
|
||||
int bw = (int)(DESIGN_BUTTON_WIDTH * scale + .5f);
|
||||
int bh = (int)(DESIGN_BUTTON_HEIGHT * scale + .5f);
|
||||
int bp = (int)(DESIGN_PADDING * scale + .5f);
|
||||
int by = (int)(DESIGN_BUTTON_AREA_Y * scale + .5f);
|
||||
|
||||
if (initialized == 0) {
|
||||
XftColorAllocName(ui->display,
|
||||
DefaultVisual(ui->display, DefaultScreen(ui->display)),
|
||||
DefaultColormap(ui->display, DefaultScreen(ui->display)),
|
||||
XftColor buttonColor;
|
||||
#if defined(__OpenBSD__)
|
||||
"#232320", &buttonColor);
|
||||
buttonColor = suwaui_set_button_fgcolor(window, "#232320");
|
||||
#elif defined(__FreeBSD__)
|
||||
"#232020", &buttonColor);
|
||||
buttonColor = suwaui_set_button_fgcolor(window, "#232020");
|
||||
#endif
|
||||
}
|
||||
initialized = 1;
|
||||
|
||||
for (int row = 1; row < NUM_ROWS; ++row) {
|
||||
for (int col = 0; col < NUM_COLS; ++col) {
|
||||
SuwaButton btn = {
|
||||
.x = padding + col * (width + padding),
|
||||
.y = start_y + (row - 1) * (height + padding),
|
||||
.width = width,
|
||||
.height = height,
|
||||
.text = btn_labels[row][col],
|
||||
.font = ui->font,
|
||||
.bg_color = BTCOL,
|
||||
.fg_color = buttonColor,
|
||||
.pressed = 0
|
||||
};
|
||||
SuwaButton btn = suwaui_add_button(bp + col * (bw + bp),
|
||||
by + (row - 1) * (bh + bp),
|
||||
bw, bh, btn_labels[row][col], window->font, BTCOL, buttonColor);
|
||||
|
||||
drawbuttons(ui, &btn, backdraw);
|
||||
suwaui_draw_button(window, &btn, backdraw);
|
||||
}
|
||||
}
|
||||
|
||||
XCopyArea(ui->display, ui->backbuf, ui->xwindow, ui->gc, 0, 0, w, h, 0, 0);
|
||||
XCopyArea(window->display, window->backbuf, window->xwindow, window->gc,
|
||||
0, 0, w, h, 0, 0);
|
||||
XftDrawDestroy(backdraw);
|
||||
XFlush(ui->display);
|
||||
XFlush(window->display);
|
||||
}
|
||||
|
||||
void handle_button_press(UiSystem *ui, int mx, int my) {
|
||||
SuwaButton *btn = find_button_at(ui, mx, my);
|
||||
void handle_button_press(SuwaWindow *window, int mx, int my) {
|
||||
SuwaButton *btn = find_button_at(window, mx, my);
|
||||
if (!btn) return;
|
||||
|
||||
btn->pressed = 1;
|
||||
XftDraw *backdraw = XftDrawCreate(ui->display, ui->backbuf,
|
||||
DefaultVisual(ui->display, DefaultScreen(ui->display)),
|
||||
DefaultColormap(ui->display, DefaultScreen(ui->display)));
|
||||
XftDraw *backdraw = XftDrawCreate(window->display, window->backbuf,
|
||||
DefaultVisual(window->display, DefaultScreen(window->display)),
|
||||
DefaultColormap(window->display, DefaultScreen(window->display)));
|
||||
if (!backdraw) {
|
||||
fprintf(stderr, "Pixmap向けXftDrawの作成に失敗。\n");
|
||||
XFreePixmap(ui->display, ui->backbuf);
|
||||
ui->backbuf = None;
|
||||
XFreePixmap(window->display, window->backbuf);
|
||||
window->backbuf = None;
|
||||
return;
|
||||
}
|
||||
|
||||
drawbuttons(ui, btn, backdraw);
|
||||
XFlush(ui->display);
|
||||
suwaui_draw_button(window, btn, backdraw);
|
||||
XFlush(window->display);
|
||||
}
|
||||
|
||||
void handle_button_release(UiSystem *ui, int mx, int my) {
|
||||
SuwaButton *btn = find_button_at(ui, mx, my);
|
||||
void handle_button_release(SuwaWindow *window, CtrlLabels *labels, int mx, int my) {
|
||||
SuwaButton *btn = find_button_at(window, mx, my);
|
||||
if (!btn) return;
|
||||
|
||||
btn->pressed = 0;
|
||||
XftDraw *backdraw = XftDrawCreate(ui->display, ui->backbuf,
|
||||
DefaultVisual(ui->display, DefaultScreen(ui->display)),
|
||||
DefaultColormap(ui->display, DefaultScreen(ui->display)));
|
||||
XftDraw *backdraw = XftDrawCreate(window->display, window->backbuf,
|
||||
DefaultVisual(window->display, DefaultScreen(window->display)),
|
||||
DefaultColormap(window->display, DefaultScreen(window->display)));
|
||||
if (!backdraw) {
|
||||
fprintf(stderr, "Pixmap向けXftDrawの作成に失敗。\n");
|
||||
XFreePixmap(ui->display, ui->backbuf);
|
||||
ui->backbuf = None;
|
||||
XFreePixmap(window->display, window->backbuf);
|
||||
window->backbuf = None;
|
||||
return;
|
||||
}
|
||||
|
||||
ui->target = ui->backbuf;
|
||||
drawbuttons(ui, btn, backdraw);
|
||||
window->target = window->backbuf;
|
||||
suwaui_draw_button(window, btn, backdraw);
|
||||
XftDrawDestroy(backdraw);
|
||||
XFlush(ui->display);
|
||||
XFlush(window->display);
|
||||
|
||||
const char *label = btn->text;
|
||||
if (strcmp(label, "C") == 0) {
|
||||
clear_calculator(ui);
|
||||
clear_calculator(labels);
|
||||
} else if (strcmp(label, "×") == 0) {
|
||||
append_to_input(ui, '*');
|
||||
append_to_input(labels, '*');
|
||||
} else if (strcmp(label, "÷") == 0) {
|
||||
append_to_input(ui, '/');
|
||||
append_to_input(labels, '/');
|
||||
} else if (strcmp(label, "<") == 0) {
|
||||
curinput[--input_pos] = '\0';
|
||||
strcpy(ui->resLabel.text, curinput[0] ? curinput : "0");
|
||||
strcpy(labels->res->text, curinput[0] ? curinput : "0");
|
||||
} else if (strcmp(label, "=") == 0) {
|
||||
double res = evaluate_simple(ui, curinput);
|
||||
if (isnan(res)) strncpy(ui->resLabel.text, "Error", 5);
|
||||
else snprintf(ui->resLabel.text, sizeof(ui->resLabel.text), "%.8g", res);
|
||||
double res = evaluate_simple(labels, curinput);
|
||||
if (isnan(res)) strncpy(labels->res->text, "Error", 5);
|
||||
else snprintf(labels->res->text, sizeof(labels->res->text), "%.8g", res);
|
||||
} else if (strlen(label) == 1) {
|
||||
append_to_input(ui, label[0]);
|
||||
append_to_input(labels, label[0]);
|
||||
}
|
||||
|
||||
control_expose(ui, &(XEvent){.type = Expose});
|
||||
window->event = (XEvent){.type = Expose};
|
||||
control_expose(window, labels);
|
||||
}
|
||||
|
||||
void handle_key_press(UiSystem *ui, XEvent *event) {
|
||||
void handle_key_press(SuwaWindow *window, CtrlLabels *labels) {
|
||||
KeySym keysym;
|
||||
char buf[32];
|
||||
int len;
|
||||
(void)len;
|
||||
|
||||
keysym = XLookupKeysym(&event->xkey, 0);
|
||||
len = XLookupString(&event->xkey, buf, sizeof(buf), &keysym, NULL);
|
||||
keysym = XLookupKeysym(&window->event.xkey, 0);
|
||||
len = XLookupString(&window->event.xkey, buf, sizeof(buf), &keysym, NULL);
|
||||
|
||||
if (keysym == XK_Q) {
|
||||
ui->isrunning = 0;
|
||||
window->isrunning = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -324,10 +302,6 @@ void handle_key_press(UiSystem *ui, XEvent *event) {
|
||||
puts("標準電卓画面");
|
||||
}
|
||||
|
||||
if (keysym == XK_S) {
|
||||
puts("関数電卓画面");
|
||||
}
|
||||
|
||||
if (keysym == XK_P) {
|
||||
puts("プログラマー電卓画面");
|
||||
}
|
||||
@@ -345,19 +319,18 @@ void handle_key_press(UiSystem *ui, XEvent *event) {
|
||||
puts("h = ヘルプ画面 Help screen");
|
||||
puts("H = 履歴画面 History screen");
|
||||
puts("B = 標準電卓画面 Basic calculator screen");
|
||||
puts("S = 関数電卓画面 Scientific calculator screen");
|
||||
puts("P = プログラマー電卓画面 Programmer calculator screen");
|
||||
}
|
||||
|
||||
if (keysym == XK_C) {
|
||||
clear_calculator(ui);
|
||||
clear_calculator(labels);
|
||||
goto redraw;
|
||||
}
|
||||
|
||||
if (keysym == XK_Return || keysym == XK_KP_Enter) {
|
||||
double res = evaluate_simple(ui, curinput);
|
||||
if (isnan(res)) strncpy(ui->resLabel.text, "Error", 5);
|
||||
else snprintf(ui->resLabel.text, sizeof(ui->resLabel.text), "%.8g", res);
|
||||
double res = evaluate_simple(labels, curinput);
|
||||
if (isnan(res)) strncpy(labels->res->text, "Error", 5);
|
||||
else snprintf(labels->res->text, sizeof(labels->res->text), "%.8g", res);
|
||||
goto redraw;
|
||||
}
|
||||
|
||||
@@ -365,7 +338,7 @@ void handle_key_press(UiSystem *ui, XEvent *event) {
|
||||
|| (keysym == XK_Delete && input_pos > 0)
|
||||
|| (keysym == XK_X && input_pos > 0)) {
|
||||
curinput[--input_pos] = '\0';
|
||||
strcpy(ui->resLabel.text, curinput[0] ? curinput : "0");
|
||||
strcpy(labels->res->text, curinput[0] ? curinput : "0");
|
||||
goto redraw;
|
||||
}
|
||||
|
||||
@@ -379,28 +352,31 @@ void handle_key_press(UiSystem *ui, XEvent *event) {
|
||||
else if (keysym == XK_KP_Decimal || keysym == XK_period) c = '.';
|
||||
|
||||
if (c) {
|
||||
append_to_input(ui, c);
|
||||
append_to_input(labels, c);
|
||||
goto redraw;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
redraw:
|
||||
control_expose(ui, &(XEvent){.type = Expose});
|
||||
window->event = (XEvent){.type = Expose};
|
||||
control_expose(window, labels);
|
||||
}
|
||||
|
||||
// void handle_mouse_hover(UiSystem *ui, XEvent *event) {
|
||||
// SuwaButton *hover = find_button_at(event->xmotion.x, event->xmotion.y);
|
||||
// void handle_mouse_hover(SuwaWindow *window) {
|
||||
// int x = window->event,xmotion.x;
|
||||
// int y = window->event,xmotion.y;
|
||||
// SuwaButton *hover = find_button_at(x, y);
|
||||
|
||||
// if (hover != hovered_btn) {
|
||||
// if (hovered_btn) {
|
||||
// hovered_btn->pressed = 0;
|
||||
// redraw_single_button(&ui, hovered_btn);
|
||||
// redraw_single_button(&window, hovered_btn);
|
||||
// }
|
||||
// hovered_btn = hover;
|
||||
|
||||
// if (hovered_btn) {
|
||||
// redraw_single_button(&ui, hovered_btn);
|
||||
// redraw_single_button(&window, hovered_btn);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
14
control.h
Normal file
14
control.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <suwaui.h>
|
||||
|
||||
typedef struct {
|
||||
SuwaLabel *res;
|
||||
SuwaLabel *problem;
|
||||
} CtrlLabels;
|
||||
|
||||
void control_expose(SuwaWindow *window, CtrlLabels *labels);
|
||||
void handle_button_press(SuwaWindow *window, int mx, int my);
|
||||
void handle_button_release(SuwaWindow *window, CtrlLabels *labels, int mx, int my);
|
||||
void handle_key_press(SuwaWindow *window, CtrlLabels *labels);
|
||||
// void handle_mouse_hover(SuwaWindow *window);
|
||||
344
include/suwaui.h
Normal file
344
include/suwaui.h
Normal file
@@ -0,0 +1,344 @@
|
||||
#pragma once
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FGCOL 0xfcfcfc
|
||||
#if defined(__OpenBSD__)
|
||||
#define BGCOL 0x232320
|
||||
#define BTSEL 0xb8b515
|
||||
#define BTCOL 0xf1ed25
|
||||
#define BTHVR 0xecea71
|
||||
#elif defined(__FreeBSD__)
|
||||
#define BGCOL 0x232020
|
||||
#define BTSEL 0xb61729
|
||||
#define BTCOL 0xee4030
|
||||
#define BTHVR 0xf35869
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(SUWAUI_IMPLEMENTS_SUWAWINDOW)
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
int start_width, start_height;
|
||||
int isrunning;
|
||||
const char *name;
|
||||
const char *version;
|
||||
const char *res_name;
|
||||
const char *class_name;
|
||||
Display *display;
|
||||
Window xwindow;
|
||||
int screen;
|
||||
Drawable target;
|
||||
GC gc;
|
||||
Visual visual;
|
||||
XftColor color;
|
||||
XftFont *font;
|
||||
Colormap colormap;
|
||||
Pixmap backbuf;
|
||||
XEvent event;
|
||||
} SuwaWindow;
|
||||
|
||||
__attribute__((unused)) static void suwaui_destroy_window(SuwaWindow *w);
|
||||
|
||||
__attribute__((unused)) static inline float get_scale(SuwaWindow *w) {
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(w->display, w->xwindow, &attr);
|
||||
float sx = (float)attr.width / w->start_width;
|
||||
float sy = (float)attr.height / w->start_height;
|
||||
return sx < sy ? sx : sy;
|
||||
}
|
||||
|
||||
__attribute__((unused)) static SuwaWindow suwaui_create_window(int x, int y, int width, int height,
|
||||
const char *software_name, const char *software_version,
|
||||
const char *res_name, const char *class_name,
|
||||
const char *font, const char *fg_color,
|
||||
int is_centered, int cannot_shrink, int cannot_grow) {
|
||||
(void)cannot_grow;
|
||||
|
||||
SuwaWindow w = {0};
|
||||
w.width = width;
|
||||
w.height = height;
|
||||
w.start_width = width;
|
||||
w.start_height = height;
|
||||
w.name = software_name;
|
||||
w.version = software_version;
|
||||
w.res_name = res_name;
|
||||
w.class_name = class_name;
|
||||
w.isrunning = 1;
|
||||
|
||||
XGCValues values;
|
||||
|
||||
w.display = XOpenDisplay(NULL);
|
||||
if (w.display == NULL) {
|
||||
fprintf(stderr, "screen open fail\n");
|
||||
return (SuwaWindow){0};
|
||||
}
|
||||
|
||||
w.screen = DefaultScreen(w.display);
|
||||
|
||||
if (is_centered > 0) {
|
||||
int sw = DisplayWidth(w.display, w.screen);
|
||||
int sh = DisplayHeight(w.display, w.screen);
|
||||
w.x = (sw - w.width) / 2;
|
||||
w.y = (sh - w.height) / 2;
|
||||
} else {
|
||||
w.x = x;
|
||||
w.y = y;
|
||||
}
|
||||
|
||||
w.xwindow = XCreateSimpleWindow(w.display,
|
||||
RootWindow(w.display, w.screen),
|
||||
w.x, w.y,
|
||||
w.width, w.height,
|
||||
1, BTCOL, BGCOL);
|
||||
if (!w.xwindow) {
|
||||
suwaui_destroy_window(&w);
|
||||
fprintf(stderr, "window create fail\n");
|
||||
return (SuwaWindow){0};
|
||||
}
|
||||
|
||||
if (cannot_shrink) {
|
||||
XSizeHints *sizeHint = XAllocSizeHints();
|
||||
if (sizeHint) {
|
||||
sizeHint->flags = PMinSize;
|
||||
sizeHint->min_width = width;
|
||||
sizeHint->min_height = height;
|
||||
XSetWMNormalHints(w.display, w.xwindow, sizeHint);
|
||||
XFree(sizeHint);
|
||||
}
|
||||
}
|
||||
|
||||
w.backbuf = XCreatePixmap(w.display, w.xwindow,
|
||||
w.width, w.height,
|
||||
DefaultDepth(w.display, w.screen));
|
||||
w.target = w.backbuf;
|
||||
|
||||
Atom net_wm_window_type = XInternAtom(w.display, "_NET_WM_WINDOW_TYPE", False);
|
||||
Atom dialog = XInternAtom(w.display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
|
||||
XChangeProperty(w.display, w.xwindow, net_wm_window_type, XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char *)&dialog, 1);
|
||||
|
||||
XStoreName(w.display, w.xwindow, w.name);
|
||||
Atom net_wm_name = XInternAtom(w.display, "_NET_WM_NAME", False);
|
||||
char displayname[16];
|
||||
snprintf(displayname, 16, "%s %s", w.name, w.version);
|
||||
XChangeProperty(w.display, w.xwindow, net_wm_name,
|
||||
XInternAtom(w.display, "UTF8_STRING", False), 8,
|
||||
PropModeReplace, (unsigned char *)displayname, strlen(displayname));
|
||||
|
||||
XClassHint *classHint = XAllocClassHint();
|
||||
if (classHint) {
|
||||
classHint->res_name = strdup(w.res_name);
|
||||
classHint->res_class = strdup(w.class_name);
|
||||
XSetClassHint(w.display, w.xwindow, classHint);
|
||||
XFree(classHint);
|
||||
}
|
||||
|
||||
XSetWindowBackground(w.display, w.xwindow, BGCOL);
|
||||
|
||||
XSelectInput(w.display, w.xwindow,
|
||||
ExposureMask
|
||||
| ButtonPressMask
|
||||
| ButtonReleaseMask
|
||||
| KeyPressMask
|
||||
// | PointerMotionMask
|
||||
// | ButtonMotionMask
|
||||
// | StructureNotifyMask
|
||||
);
|
||||
|
||||
w.gc = XCreateGC(w.display, w.xwindow, 0, &values);
|
||||
if (!w.gc) {
|
||||
suwaui_destroy_window(&w);
|
||||
fprintf(stderr, "gc create fail\n");
|
||||
return (SuwaWindow){0};
|
||||
}
|
||||
|
||||
w.visual = *DefaultVisual(w.display, w.screen);
|
||||
|
||||
w.colormap = XCreateColormap(w.display, w.xwindow,
|
||||
&w.visual, AllocNone);
|
||||
if (w.colormap == None) {
|
||||
suwaui_destroy_window(&w);
|
||||
fprintf(stderr, "calor map create fail\n");
|
||||
return (SuwaWindow){0};
|
||||
}
|
||||
|
||||
w.font = XftFontOpenName(w.display, w.screen, font);
|
||||
if (!w.font) {
|
||||
suwaui_destroy_window(&w);
|
||||
fprintf(stderr, "font create fail\n");
|
||||
return (SuwaWindow){0};
|
||||
}
|
||||
|
||||
if (!XftColorAllocName(w.display, &w.visual,
|
||||
w.colormap, fg_color, &w.color)) {
|
||||
suwaui_destroy_window(&w);
|
||||
fprintf(stderr, "color estimate fail\n");
|
||||
return (SuwaWindow){0};
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
__attribute__((unused)) static void suwaui_destroy_window(SuwaWindow *w) {
|
||||
if (w->font) XftFontClose(w->display, w->font);
|
||||
|
||||
if (w->gc) XFreeGC(w->display, w->gc);
|
||||
if (w->backbuf) {
|
||||
XFreePixmap(w->display, w->backbuf);
|
||||
w->backbuf = None;
|
||||
}
|
||||
if (w->xwindow) XDestroyWindow(w->display, w->xwindow);
|
||||
if (w->display) XCloseDisplay(w->display);
|
||||
}
|
||||
#endif // SUWAUI_IMPLEMENTS_SUWAWINDOW
|
||||
|
||||
#if defined(SUWAUI_IMPLEMENTS_SUWATABS)
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
} SuwaTab;
|
||||
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
} SuwaTabs;
|
||||
#endif // SUWAUI_IMPLEMENTS_SUWATABS
|
||||
|
||||
#if defined(SUWAUI_IMPLEMENTS_SUWABUTTON)
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
const char *text;
|
||||
XftFont *font;
|
||||
int bg_color;
|
||||
XftColor fg_color;
|
||||
int pressed; // 0 = 普通、1 = 押している
|
||||
} SuwaButton;
|
||||
|
||||
// __attribute__((unused)) static void suwaui_del_button(SuwaWindow *window, SuwaButton *button);
|
||||
|
||||
__attribute__((unused)) static XftColor suwaui_set_button_fgcolor(SuwaWindow *window, const char *color) {
|
||||
XftColor xcolor;
|
||||
XftColorAllocName(window->display,
|
||||
DefaultVisual(window->display, DefaultScreen(window->display)),
|
||||
DefaultColormap(window->display, DefaultScreen(window->display)),
|
||||
color, &xcolor);
|
||||
|
||||
return xcolor;
|
||||
}
|
||||
|
||||
__attribute__((unused)) static void suwaui_draw_button(SuwaWindow *window, SuwaButton *btn, XftDraw *xftdraw) {
|
||||
unsigned long curbg = btn->pressed ? BTSEL : btn->bg_color;
|
||||
XSetForeground(window->display, window->gc, curbg);
|
||||
XFillRectangle(window->display, window->target, window->gc, btn->x, btn->y,
|
||||
btn->width, btn->height);
|
||||
|
||||
// 文字の中央に
|
||||
if (btn->text && window->font && xftdraw) {
|
||||
const FcChar8 *str = (const FcChar8 *)btn->text;
|
||||
int len = strlen((const char *)str);
|
||||
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(window->display, window->font, str, len, &extents);
|
||||
|
||||
int text_w = extents.xOff;
|
||||
int text_h = window->font->ascent + window->font->descent;
|
||||
|
||||
int tx = btn->x + (btn->width - text_w) / 2;
|
||||
int ty = btn->y + (btn->height - text_h) / 2 + window->font->ascent;
|
||||
|
||||
XftDrawStringUtf8(xftdraw, &btn->fg_color, window->font, tx, ty,
|
||||
(FcChar8 *)btn->text, len);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((unused)) static SuwaButton suwaui_add_button(int x, int y, int width, int height,
|
||||
const char *text, XftFont *font, int bg_color, XftColor fg_color) {
|
||||
SuwaButton button = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.text = text,
|
||||
.font = font,
|
||||
.bg_color = bg_color,
|
||||
.fg_color = fg_color,
|
||||
.pressed = 0
|
||||
};
|
||||
|
||||
return button;
|
||||
}
|
||||
#endif // SUWAUI_IMPLEMENTS_SUWABUTTON
|
||||
|
||||
#if defined(SUWAUI_IMPLEMENTS_SUWALABEL)
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
char text[64];
|
||||
XftFont *font;
|
||||
XftColor fg_color;
|
||||
} SuwaLabel;
|
||||
|
||||
__attribute__((unused)) static void suwaui_del_label(SuwaWindow *window, SuwaLabel *label);
|
||||
|
||||
__attribute__((unused)) static SuwaLabel suwaui_add_label(SuwaWindow *window,
|
||||
int x, int y, int width, int height, char text[64], const char *font,
|
||||
const char *fg_color, int rtl) {
|
||||
(void)width;
|
||||
(void)height;
|
||||
SuwaLabel label = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height
|
||||
};
|
||||
|
||||
label.font = XftFontOpenName(window->display, window->screen, font);
|
||||
if (!label.font) {
|
||||
fprintf(stderr, "font create fail\n");
|
||||
return (SuwaLabel){0};
|
||||
}
|
||||
|
||||
strncpy(label.text, text ? text : "", sizeof(label.text) - 1);
|
||||
label.text[sizeof(label.text)-1] = '\0';
|
||||
|
||||
const FcChar8 *txt = (const FcChar8 *)label.text;
|
||||
int len = strlen((const char *)txt);
|
||||
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(window->display, label.font, txt, len, &extents);
|
||||
|
||||
if (rtl > 0) {
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(window->display, window->xwindow, &attr);
|
||||
int w = attr.width;
|
||||
label.x = w - label.x - extents.xOff;
|
||||
}
|
||||
|
||||
if (!XftColorAllocName(window->display,
|
||||
DefaultVisual(window->display, DefaultScreen(window->display)),
|
||||
DefaultColormap(window->display, DefaultScreen(window->display)),
|
||||
fg_color, &label.fg_color)) {
|
||||
suwaui_del_label(window, &label);
|
||||
fprintf(stderr, "color estimate fail\n");
|
||||
return (SuwaLabel){0};
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
__attribute__((unused)) static void suwaui_del_label(SuwaWindow *window, SuwaLabel *label) {
|
||||
if (label->font) XftFontClose(window->display, label->font);
|
||||
}
|
||||
#endif // SUWAUI_IMPLEMENTS_SUWALABEL
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
252
main.c
252
main.c
@@ -1,243 +1,79 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include "src/utils.h"
|
||||
#include "src/control.h"
|
||||
#include "control.h"
|
||||
|
||||
const char *sofname = "ucalc";
|
||||
const char *version = "0.0.0";
|
||||
const char *disname = "Unix Calc";
|
||||
|
||||
int main() {
|
||||
UiSystem ui;
|
||||
ui.isrunning = 1;
|
||||
ui.window.width = 382;
|
||||
ui.window.height = 534;
|
||||
XEvent event;
|
||||
int screen;
|
||||
XGCValues values;
|
||||
|
||||
ui.display = XOpenDisplay(NULL);
|
||||
if (ui.display == NULL) {
|
||||
fprintf(stderr, "画面を開けられません。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
screen = DefaultScreen(ui.display);
|
||||
|
||||
int sw = DisplayWidth(ui.display, screen);
|
||||
int sh = DisplayHeight(ui.display, screen);
|
||||
ui.window.x = (sw - ui.window.width) / 3;
|
||||
ui.window.y = (sh - ui.window.height) / 2;
|
||||
|
||||
ui.xwindow = XCreateSimpleWindow(ui.display,
|
||||
RootWindow(ui.display, screen),
|
||||
ui.window.x, ui.window.y,
|
||||
ui.window.width, ui.window.height,
|
||||
1, BTCOL, BGCOL);
|
||||
if (!ui.xwindow) {
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "ウィンドウを作成に失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
XSizeHints *sizeHint = XAllocSizeHints();
|
||||
if (sizeHint) {
|
||||
sizeHint->flags = PMinSize;
|
||||
sizeHint->min_width = 382;
|
||||
sizeHint->min_height = 534;
|
||||
XSetWMNormalHints(ui.display, ui.xwindow, sizeHint);
|
||||
XFree(sizeHint);
|
||||
}
|
||||
|
||||
ui.backbuf = XCreatePixmap(ui.display, ui.xwindow,
|
||||
ui.window.width, ui.window.height,
|
||||
DefaultDepth(ui.display, screen));
|
||||
ui.target = ui.backbuf;
|
||||
|
||||
Atom net_wm_window_type = XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE", False);
|
||||
Atom dialog = XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
|
||||
XChangeProperty(ui.display, ui.xwindow, net_wm_window_type, XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char *)&dialog, 1);
|
||||
|
||||
XStoreName(ui.display, ui.xwindow, disname);
|
||||
Atom net_wm_name = XInternAtom(ui.display, "_NET_WM_NAME", False);
|
||||
char displayname[16];
|
||||
snprintf(displayname, 16, "%s %s", disname, version);
|
||||
XChangeProperty(ui.display, ui.xwindow, net_wm_name,
|
||||
XInternAtom(ui.display, "UTF8_STRING", False), 8,
|
||||
PropModeReplace, (unsigned char *)displayname, strlen(displayname));
|
||||
|
||||
XClassHint *classHint = XAllocClassHint();
|
||||
if (classHint) {
|
||||
classHint->res_name = "unixcalc";
|
||||
classHint->res_class = "UnixCalc";
|
||||
XSetClassHint(ui.display, ui.xwindow, classHint);
|
||||
XFree(classHint);
|
||||
}
|
||||
|
||||
XSetWindowBackground(ui.display, ui.xwindow, BGCOL);
|
||||
|
||||
XSelectInput(ui.display, ui.xwindow,
|
||||
ExposureMask
|
||||
| ButtonPressMask
|
||||
| ButtonReleaseMask
|
||||
| KeyPressMask
|
||||
// | PointerMotionMask
|
||||
// | ButtonMotionMask
|
||||
// | StructureNotifyMask
|
||||
);
|
||||
|
||||
ui.gc = XCreateGC(ui.display, ui.xwindow, 0, &values);
|
||||
if (!ui.gc) {
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "GCを作成に失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ui.visual = *DefaultVisual(ui.display, screen);
|
||||
|
||||
ui.colormap = XCreateColormap(ui.display, ui.xwindow, &ui.visual, AllocNone);
|
||||
if (ui.colormap == None) {
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "カラーマップを作成に失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(ui.display, ui.xwindow, &attr);
|
||||
int w = attr.width;
|
||||
|
||||
{
|
||||
#if defined(__OpenBSD__)
|
||||
ui.resLabel.font = XftFontOpenName(ui.display, screen, "Noto Sans CJK-48");
|
||||
SuwaWindow window = suwaui_create_window(
|
||||
500, 400, 382, 534,
|
||||
disname, version, "unixcalc", "UnixCalc",
|
||||
"Noto Sans CJK-8", "#232320",
|
||||
0, 1, 0);
|
||||
SuwaLabel resLabel = suwaui_add_label(&window, 20, 180, 0, 0, "0",
|
||||
"Noto Sans CJK-48", "#f1ed25", 1);
|
||||
SuwaLabel problemLabel = suwaui_add_label(&window, 20, 80, 0, 0, "",
|
||||
"Noto Sans CJK-12", "#b8b515", 1);
|
||||
#elif defined(__FreeBSD__)
|
||||
ui.resLabel.font = XftFontOpenName(ui.display, screen, "Noto Sans CJK-72");
|
||||
SuwaWindow window = suwaui_create_window(
|
||||
20, 40, 382, 534,
|
||||
disname, version, "unixcalc", "UnixCalc",
|
||||
"Noto Sans CJK-12", "#232020",
|
||||
0, 1, 0);
|
||||
SuwaLabel resLabel = suwaui_add_label(&window, 20, 180, 0, 0, "0",
|
||||
"Noto Sans CJK-72", "#ee4030", 1);
|
||||
SuwaLabel problemLabel = suwaui_add_label(&window, 20, 80, 0, 0, "",
|
||||
"Noto Sans CJK-24", "#b61729", 1);
|
||||
#endif
|
||||
if (!ui.resLabel.font) {
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "解決フォントの読み込みに失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ui.resLabel.text[0] = '0';
|
||||
ui.resLabel.text[1] = '\0';
|
||||
CtrlLabels lbl = {
|
||||
.res = &resLabel,
|
||||
.problem = &problemLabel
|
||||
};
|
||||
|
||||
const FcChar8 *text = (const FcChar8 *)ui.resLabel.text;
|
||||
int len = strlen((const char *)text);
|
||||
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(ui.display, ui.resLabel.font, text, len, &extents);
|
||||
|
||||
ui.resLabel.x = w - 20 - extents.xOff;
|
||||
ui.resLabel.y = 180;
|
||||
if (!XftColorAllocName(ui.display,
|
||||
DefaultVisual(ui.display, DefaultScreen(ui.display)),
|
||||
DefaultColormap(ui.display, DefaultScreen(ui.display)),
|
||||
#if defined(__OpenBSD__)
|
||||
"#f1ed25", &ui.resLabel.fg_color)) {
|
||||
#elif defined(__FreeBSD__)
|
||||
"#ee4030", &ui.resLabel.fg_color)) {
|
||||
#endif
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "色の役割に失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
#if defined(__OpenBSD__)
|
||||
ui.problemLabel.font = XftFontOpenName(ui.display, screen, "Noto Sans CJK-12");
|
||||
#elif defined(__FreeBSD__)
|
||||
ui.problemLabel.font = XftFontOpenName(ui.display, screen, "Noto Sans CJK-24");
|
||||
#endif
|
||||
if (!ui.problemLabel.font) {
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "問題フォントの読み込みに失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ui.problemLabel.text[0] = '\0';
|
||||
|
||||
const FcChar8 *text = (const FcChar8 *)ui.problemLabel.text;
|
||||
int len = strlen((const char *)text);
|
||||
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(ui.display, ui.problemLabel.font, text, len, &extents);
|
||||
|
||||
ui.problemLabel.x = w - 20 - extents.xOff;
|
||||
ui.problemLabel.y = 80;
|
||||
if (!XftColorAllocName(ui.display,
|
||||
DefaultVisual(ui.display, DefaultScreen(ui.display)),
|
||||
DefaultColormap(ui.display, DefaultScreen(ui.display)),
|
||||
#if defined(__OpenBSD__)
|
||||
"#b8b515", &ui.problemLabel.fg_color)) {
|
||||
#elif defined(__FreeBSD__)
|
||||
"#b61729", &ui.problemLabel.fg_color)) {
|
||||
#endif
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "色の役割に失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
ui.font = XftFontOpenName(ui.display, screen, "Noto Sans CJK-8");
|
||||
#elif defined(__FreeBSD__)
|
||||
ui.font = XftFontOpenName(ui.display, screen, "Noto Sans CJK-12");
|
||||
#endif
|
||||
if (!ui.font) {
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "フォントの読み込みに失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
if (!XftColorAllocName(ui.display, &ui.visual, ui.colormap, "#232320", &ui.color)) {
|
||||
#elif defined(__FreeBSD__)
|
||||
if (!XftColorAllocName(ui.display, &ui.visual, ui.colormap, "#232020", &ui.color)) {
|
||||
#endif
|
||||
cleanup(&ui);
|
||||
fprintf(stderr, "色の役割に失敗。\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
XMapWindow(ui.display, ui.xwindow);
|
||||
XMapWindow(window.display, window.xwindow);
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(ui.display, ui.xwindow, &attr);
|
||||
XGetWindowAttributes(window.display, window.xwindow, &attr);
|
||||
XEvent fake = { .type = Expose };
|
||||
fake.xexpose.window = ui.xwindow;
|
||||
fake.xexpose.window = window.xwindow;
|
||||
fake.xexpose.width = attr.width;
|
||||
fake.xexpose.height = attr.height;
|
||||
control_expose(&ui, &event);
|
||||
control_expose(&window, &lbl);
|
||||
}
|
||||
|
||||
while (ui.isrunning) {
|
||||
XNextEvent(ui.display, &event);
|
||||
while (window.isrunning) {
|
||||
XNextEvent(window.display, &window.event);
|
||||
|
||||
switch (event.type) {
|
||||
switch (window.event.type) {
|
||||
case Expose:
|
||||
case ConfigureNotify:
|
||||
XClearWindow(ui.display, ui.xwindow);
|
||||
control_expose(&ui, &event);
|
||||
XClearWindow(window.display, window.xwindow);
|
||||
control_expose(&window, &lbl);
|
||||
break;
|
||||
case ButtonPress:
|
||||
if (event.xbutton.button == Button1) {
|
||||
handle_button_press(&ui, event.xbutton.x, event.xbutton.y);
|
||||
if (window.event.xbutton.button == Button1) {
|
||||
int x = window.event.xbutton.x;
|
||||
int y = window.event.xbutton.y;
|
||||
handle_button_press(&window, x, y);
|
||||
break;
|
||||
}
|
||||
case ButtonRelease:
|
||||
if (event.xbutton.button == Button1) {
|
||||
handle_button_release(&ui, event.xbutton.x, event.xbutton.y);
|
||||
if (window.event.xbutton.button == Button1) {
|
||||
int x = window.event.xbutton.x;
|
||||
int y = window.event.xbutton.y;
|
||||
handle_button_release(&window, &lbl, x, y);
|
||||
break;
|
||||
}
|
||||
case KeyPress:
|
||||
handle_key_press(&ui, &event);
|
||||
handle_key_press(&window, &lbl);
|
||||
break;
|
||||
// case MotionNotify:
|
||||
// handle_mouse_hover(&ui, &event);
|
||||
// handle_mouse_hover(&window);
|
||||
// break;
|
||||
case ClientMessage:
|
||||
// WM_DELETE_WINDOW
|
||||
@@ -245,7 +81,9 @@ int main() {
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(&ui);
|
||||
suwaui_del_label(&window, &problemLabel);
|
||||
suwaui_del_label(&window, &resLabel);
|
||||
suwaui_destroy_window(&window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
void control_expose(UiSystem *ui, XEvent *event);
|
||||
void handle_button_press(UiSystem *ui, int mx, int my);
|
||||
void handle_button_release(UiSystem *ui, int mx, int my);
|
||||
void handle_key_press(UiSystem *ui, XEvent *event);
|
||||
void handle_mouse_hover(UiSystem *ui, XEvent *event);
|
||||
@@ -1,28 +0,0 @@
|
||||
#include "display.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void drawbuttons(UiSystem *ui, SuwaButton *btn, XftDraw *xftdraw) {
|
||||
unsigned long curbg = btn->pressed ? BTSEL : btn->bg_color;
|
||||
XSetForeground(ui->display, ui->gc, curbg);
|
||||
XFillRectangle(ui->display, ui->target, ui->gc, btn->x, btn->y,
|
||||
btn->width, btn->height);
|
||||
|
||||
// 文字の中央に
|
||||
if (btn->text && ui->font && xftdraw) {
|
||||
const FcChar8 *str = (const FcChar8 *)btn->text;
|
||||
int len = strlen((const char *)str);
|
||||
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(ui->display, ui->font, str, len, &extents);
|
||||
|
||||
int text_w = extents.xOff;
|
||||
int text_h = ui->font->ascent + ui->font->descent;
|
||||
|
||||
int tx = btn->x + (btn->width - text_w) / 2;
|
||||
int ty = btn->y + (btn->height - text_h) / 2 + ui->font->ascent;
|
||||
|
||||
XftDrawStringUtf8(xftdraw, &btn->fg_color, ui->font, tx, ty,
|
||||
(FcChar8 *)btn->text, len);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
void drawbuttons(UiSystem *ui, SuwaButton *btn, XftDraw *xftdraw);
|
||||
53
src/ui.h
53
src/ui.h
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#define FGCOL 0xfcfcfc
|
||||
#if defined(__OpenBSD__)
|
||||
#define BGCOL 0x232320
|
||||
#define BTSEL 0xb8b515
|
||||
#define BTCOL 0xf1ed25
|
||||
#define BTHVR 0xecea71
|
||||
#elif defined(__FreeBSD__)
|
||||
#define BGCOL 0x232020
|
||||
#define BTSEL 0xb61729
|
||||
#define BTCOL 0xee4030
|
||||
#define BTHVR 0xf35869
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
} SuwaWindow;
|
||||
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
const char *text;
|
||||
XftFont *font;
|
||||
int bg_color;
|
||||
XftColor fg_color;
|
||||
int pressed; // 0 = 普通、1 = 押している
|
||||
} SuwaButton;
|
||||
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
char text[64];
|
||||
XftFont *font;
|
||||
XftColor fg_color;
|
||||
} SuwaLabel;
|
||||
|
||||
typedef struct {
|
||||
int isrunning;
|
||||
Display *display;
|
||||
Window xwindow;
|
||||
Drawable target;
|
||||
GC gc;
|
||||
Visual visual;
|
||||
XftColor color;
|
||||
XftFont *font;
|
||||
Colormap colormap;
|
||||
Pixmap backbuf;
|
||||
SuwaWindow window;
|
||||
SuwaLabel resLabel;
|
||||
SuwaLabel problemLabel;
|
||||
} UiSystem;
|
||||
17
src/utils.c
17
src/utils.c
@@ -1,17 +0,0 @@
|
||||
#include "utils.h"
|
||||
|
||||
void cleanup(UiSystem *ui) {
|
||||
// フォント
|
||||
if (ui->resLabel.font) XftFontClose(ui->display, ui->resLabel.font);
|
||||
if (ui->problemLabel.font) XftFontClose(ui->display, ui->problemLabel.font);
|
||||
if (ui->font) XftFontClose(ui->display, ui->font);
|
||||
|
||||
// その他
|
||||
if (ui->gc) XFreeGC(ui->display, ui->gc);
|
||||
if (ui->backbuf) {
|
||||
XFreePixmap(ui->display, ui->backbuf);
|
||||
ui->backbuf = None;
|
||||
}
|
||||
if (ui->xwindow) XDestroyWindow(ui->display, ui->xwindow);
|
||||
if (ui->display) XCloseDisplay(ui->display);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
void cleanup(UiSystem *ui);
|
||||
Reference in New Issue
Block a user