add: crosshair support

This commit is contained in:
Jeremy Attali 2019-11-20 23:16:15 -05:00
parent 0b3e95a7cd
commit 243f201ec0
4 changed files with 219 additions and 89 deletions

View File

@ -26,17 +26,19 @@ static void tools_menu_button_clear_clicked_handler(
static void tools_menu_button_brush_toggle_handler(GtkToggleButton *source,
struct swappy_state *state) {
printf("brush toggled: %d\n", gtk_toggle_button_get_active(source));
bool is_active = gtk_toggle_button_get_active(source) == 1;
state->is_mode_brush = is_active;
state->is_mode_text = !is_active;
state->mode = SWAPPY_PAINT_MODE_BRUSH;
}
static void tools_menu_button_text_toggle_handler(GtkToggleButton *source,
struct swappy_state *state) {
printf("text toggled: %d\n", gtk_toggle_button_get_active(source));
bool is_active = gtk_toggle_button_get_active(source) == 1;
state->is_mode_brush = !is_active;
state->is_mode_text = is_active;
state->mode = SWAPPY_PAINT_MODE_TEXT;
}
static void tools_menu_button_shape_toggle_handler(GtkToggleButton *source,
struct swappy_state *state) {
printf("shape toggled: %d\n", gtk_toggle_button_get_active(source));
state->mode = SWAPPY_PAINT_MODE_RECTANGLE;
}
static gboolean keypress_handler(GtkWidget *widget, GdkEventKey *event,
@ -123,7 +125,11 @@ static void brush_add_point(struct swappy_state *state, double x, double y,
static void draw_area_button_press_handler(GtkWidget *widget,
GdkEventButton *event,
struct swappy_state *state) {
if (state->is_mode_brush) {
if (!(event->state & GDK_BUTTON1_MASK)) {
return;
}
if (state->mode == SWAPPY_PAINT_MODE_BRUSH) {
brush_add_point(state, event->x, event->y, SWAPPY_BRUSH_POINT_FIRST);
gtk_widget_queue_draw(state->area);
}
@ -132,7 +138,11 @@ static void draw_area_button_press_handler(GtkWidget *widget,
static void draw_area_button_release_handler(GtkWidget *widget,
GdkEventButton *event,
struct swappy_state *state) {
if (state->is_mode_brush) {
if (!(event->state & GDK_BUTTON1_MASK)) {
return;
}
if (state->mode == SWAPPY_PAINT_MODE_BRUSH) {
brush_add_point(state, event->x, event->y, SWAPPY_BRUSH_POINT_LAST);
gtk_widget_queue_draw(state->area);
}
@ -141,81 +151,32 @@ static void draw_area_button_release_handler(GtkWidget *widget,
static void draw_area_motion_notify_handler(GtkWidget *widget,
GdkEventMotion *event,
struct swappy_state *state) {
if (state->is_mode_brush) {
brush_add_point(state, event->x, event->y, SWAPPY_BRUSH_POINT_WITHIN);
gtk_widget_queue_draw(state->area);
GdkDisplay *display = gdk_display_get_default();
GdkWindow *window = event->window;
if (state->mode == SWAPPY_PAINT_MODE_BRUSH) {
GdkCursor *crosshair = gdk_cursor_new_for_display(display, GDK_CROSSHAIR);
gdk_window_set_cursor(window, crosshair);
if (event->state & GDK_BUTTON1_MASK) {
brush_add_point(state, event->x, event->y, SWAPPY_BRUSH_POINT_WITHIN);
gtk_widget_queue_draw(state->area);
}
} else {
gdk_window_set_cursor(window, NULL);
}
}
static void build_layout_drawing_area(struct swappy_state *state,
GtkWidget *parent) {
GtkWidget *area = gtk_drawing_area_new();
state->area = area;
gtk_widget_set_size_request(area, state->width, state->height);
gtk_container_add(GTK_CONTAINER(parent), area);
gtk_widget_add_events(area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON1_MOTION_MASK);
g_signal_connect(G_OBJECT(area), "draw", G_CALLBACK(draw_area_handler),
state);
g_signal_connect(G_OBJECT(area), "button-press-event",
G_CALLBACK(draw_area_button_press_handler), state);
g_signal_connect(G_OBJECT(area), "button-release-event",
G_CALLBACK(draw_area_button_release_handler), state);
g_signal_connect(G_OBJECT(area), "motion-notify-event",
G_CALLBACK(draw_area_motion_notify_handler), state);
}
static void build_layout_tools_menu(struct swappy_state *state,
GtkWidget *parent) {
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
GtkWidget *brush = gtk_radio_button_new_with_label(NULL, "Brush");
GtkWidget *text = gtk_radio_button_new_with_label_from_widget(
GTK_RADIO_BUTTON(brush), "Text");
GtkWidget *clear = gtk_button_new_with_label("Reset");
gtk_box_set_homogeneous(GTK_BOX(box), TRUE);
gtk_container_add(GTK_CONTAINER(box), brush);
gtk_container_add(GTK_CONTAINER(box), text);
gtk_container_add(GTK_CONTAINER(box), clear);
gtk_container_add(GTK_CONTAINER(parent), box);
g_signal_connect(brush, "toggled",
G_CALLBACK(tools_menu_button_brush_toggle_handler), state);
g_signal_connect(text, "toggled",
G_CALLBACK(tools_menu_button_text_toggle_handler), state);
g_signal_connect(clear, "clicked",
G_CALLBACK(tools_menu_button_clear_clicked_handler), state);
}
static void build_layout(struct swappy_state *state) {
return;
GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
build_layout_tools_menu(state, vbox);
build_layout_drawing_area(state, vbox);
gtk_container_add(GTK_CONTAINER(state->window), vbox);
gtk_container_set_border_width(GTK_CONTAINER(state->window), 2);
g_signal_connect(G_OBJECT(state->window), "key_press_event",
G_CALLBACK(keypress_handler), state);
gtk_widget_show_all(GTK_WIDGET(state->window));
}
static void print_hello(GtkWidget *widget, gpointer data) {
g_print("Hello World\n");
}
static bool build_ui(struct swappy_state *state) {
GtkBuilder *builder;
GObject *container;
GObject *button;
GObject *brush;
GObject *text;
GObject *shape;
GtkWidget *area;
GObject *clear;
GError *error = NULL;
/* Construct a GtkBuilder instance and load our UI description */
builder = gtk_builder_new();
if (gtk_builder_add_from_file(builder, "swappy.ui", &error) == 0) {
@ -226,21 +187,38 @@ static bool build_ui(struct swappy_state *state) {
/* Connect signal handlers to the constructed widgets. */
container = gtk_builder_get_object(builder, "container");
brush = gtk_builder_get_object(builder, "brush");
text = gtk_builder_get_object(builder, "text");
shape = gtk_builder_get_object(builder, "shape");
clear = gtk_builder_get_object(builder, "clear");
area = GTK_WIDGET(gtk_builder_get_object(builder, "paint_area"));
gtk_container_add(GTK_CONTAINER(state->window), GTK_WIDGET(container));
g_signal_connect(G_OBJECT(state->window), "key_press_event",
G_CALLBACK(keypress_handler), state);
g_signal_connect(brush, "toggled",
G_CALLBACK(tools_menu_button_brush_toggle_handler), state);
g_signal_connect(text, "toggled",
G_CALLBACK(tools_menu_button_text_toggle_handler), state);
g_signal_connect(shape, "toggled",
G_CALLBACK(tools_menu_button_shape_toggle_handler), state);
g_signal_connect(clear, "clicked",
G_CALLBACK(tools_menu_button_clear_clicked_handler), state);
button = gtk_builder_get_object(builder, "button1");
g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
button = gtk_builder_get_object(builder, "button2");
g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
button = gtk_builder_get_object(builder, "quit");
g_signal_connect(button, "clicked", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_set_size_request(area, state->width, state->height);
gtk_widget_add_events(area, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON1_MOTION_MASK);
g_signal_connect(area, "draw", G_CALLBACK(draw_area_handler), state);
g_signal_connect(area, "button-press-event",
G_CALLBACK(draw_area_button_press_handler), state);
g_signal_connect(area, "button-release-event",
G_CALLBACK(draw_area_button_release_handler), state);
g_signal_connect(area, "motion-notify-event",
G_CALLBACK(draw_area_motion_notify_handler), state);
state->area = area;
gtk_widget_show_all(GTK_WIDGET(state->window));
return true;
@ -249,7 +227,7 @@ static bool build_ui(struct swappy_state *state) {
static void application_activate(GtkApplication *app, void *data) {
struct swappy_state *state = data;
// Create a normal GTK window however you like
// Create a normal GTK vbox however you like
GtkWindow *window = GTK_WINDOW(gtk_application_window_new(app));
state->window = window;
@ -276,7 +254,6 @@ static void application_activate(GtkApplication *app, void *data) {
printf("window has sizes %dx%d\n", state->width, state->height);
build_layout(state);
build_ui(state);
}

View File

@ -13,6 +13,12 @@ enum swappy_brush_point_kind {
SWAPPY_BRUSH_POINT_LAST, /* A point at the end of brush batch */
};
enum swappy_paint_mode_type {
SWAPPY_PAINT_MODE_BRUSH = 0, /* Brush mode to draw arbitrary shapes */
SWAPPY_PAINT_MODE_TEXT, /* Mode to draw texts */
SWAPPY_PAINT_MODE_RECTANGLE, /* Rectangle shapes */
};
struct swappy_brush_point {
double x;
double y;
@ -40,8 +46,8 @@ struct swappy_state {
struct zwlr_layer_surface_v1 *layer_surface;
bool should_exit;
bool is_mode_brush;
bool is_mode_text;
enum swappy_paint_mode_type mode;
int width;
int height;

2
main.c
View File

@ -16,7 +16,7 @@ int main(int argc, char *argv[]) {
state.argc = argc;
state.argv = argv;
state.is_mode_brush = true;
state.mode = SWAPPY_PAINT_MODE_BRUSH;
sprintf(state.image, "%s", "/home/jattali/Desktop/sway.png");

147
swappy.ui Normal file
View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkBox" id="container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="container_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkBox" id="paint_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkRadioButton" id="brush">
<property name="label" translatable="yes">Brush</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">text</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="text">
<property name="label" translatable="yes">Text</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">brush</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="shape">
<property name="label" translatable="yes">Shape</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">brush</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="control_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="copy">
<property name="label" translatable="yes">Copy</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="clear">
<property name="label" translatable="yes">Clear</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="paint_area">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>