mirror of https://github.com/bsnes-emu/bsnes.git
178 lines
5.8 KiB
C++
178 lines
5.8 KiB
C++
namespace phoenix {
|
|
|
|
static void Canvas_drop(GtkWidget* widget, GdkDragContext* context, signed x, signed y,
|
|
GtkSelectionData* data, unsigned type, unsigned timestamp, Canvas* canvas) {
|
|
if(!canvas->state.droppable) return;
|
|
lstring paths = DropPaths(data);
|
|
if(paths.empty()) return;
|
|
if(canvas->onDrop) canvas->onDrop(paths);
|
|
}
|
|
|
|
static signed Canvas_expose(GtkWidget* widget, GdkEventExpose* event, Canvas* self) {
|
|
self->p.onExpose(event);
|
|
return true;
|
|
}
|
|
|
|
static signed Canvas_mouseLeave(GtkWidget* widget, GdkEventButton* event, Canvas* self) {
|
|
if(self->onMouseLeave) self->onMouseLeave();
|
|
return true;
|
|
}
|
|
|
|
static signed Canvas_mouseMove(GtkWidget* widget, GdkEventButton* event, Canvas* self) {
|
|
if(self->onMouseMove) self->onMouseMove({(signed)event->x, (signed)event->y});
|
|
return true;
|
|
}
|
|
|
|
static signed Canvas_mousePress(GtkWidget* widget, GdkEventButton* event, Canvas* self) {
|
|
if(self->onMousePress) switch(event->button) {
|
|
case 1: self->onMousePress(Mouse::Button::Left); break;
|
|
case 2: self->onMousePress(Mouse::Button::Middle); break;
|
|
case 3: self->onMousePress(Mouse::Button::Right); break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static signed Canvas_mouseRelease(GtkWidget* widget, GdkEventButton* event, Canvas* self) {
|
|
if(self->onMouseRelease) switch(event->button) {
|
|
case 1: self->onMouseRelease(Mouse::Button::Left); break;
|
|
case 2: self->onMouseRelease(Mouse::Button::Middle); break;
|
|
case 3: self->onMouseRelease(Mouse::Button::Right); break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Size pCanvas::minimumSize() {
|
|
return {canvas.state.width, canvas.state.height};
|
|
}
|
|
|
|
void pCanvas::setDroppable(bool droppable) {
|
|
gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY);
|
|
if(droppable) gtk_drag_dest_add_uri_targets(gtkWidget);
|
|
}
|
|
|
|
void pCanvas::setGeometry(Geometry geometry) {
|
|
if(canvas.state.width == 0 || canvas.state.height == 0) rasterize();
|
|
unsigned width = canvas.state.width;
|
|
unsigned height = canvas.state.height;
|
|
if(width == 0) width = widget.state.geometry.width;
|
|
if(height == 0) height = widget.state.geometry.height;
|
|
|
|
if(width < geometry.width) {
|
|
geometry.x += (geometry.width - width) / 2;
|
|
geometry.width = width;
|
|
}
|
|
|
|
if(height < geometry.height) {
|
|
geometry.y += (geometry.height - height) / 2;
|
|
geometry.height = height;
|
|
}
|
|
|
|
pWidget::setGeometry(geometry);
|
|
}
|
|
|
|
void pCanvas::setMode(Canvas::Mode mode) {
|
|
rasterize(), redraw();
|
|
}
|
|
|
|
void pCanvas::setSize(Size size) {
|
|
rasterize(), redraw();
|
|
}
|
|
|
|
void pCanvas::constructor() {
|
|
gtkWidget = gtk_drawing_area_new();
|
|
//gtk_widget_set_double_buffered(gtkWidget, false);
|
|
gtk_widget_add_events(gtkWidget,
|
|
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK);
|
|
g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Canvas_mousePress), (gpointer)&canvas);
|
|
g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Canvas_mouseRelease), (gpointer)&canvas);
|
|
g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Canvas_drop), (gpointer)&canvas);
|
|
g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Canvas_expose), (gpointer)&canvas);
|
|
g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Canvas_mouseLeave), (gpointer)&canvas);
|
|
g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Canvas_mouseMove), (gpointer)&canvas);
|
|
|
|
setDroppable(canvas.state.droppable);
|
|
rasterize(), redraw();
|
|
}
|
|
|
|
void pCanvas::destructor() {
|
|
release();
|
|
gtk_widget_destroy(gtkWidget);
|
|
}
|
|
|
|
void pCanvas::orphan() {
|
|
destructor();
|
|
constructor();
|
|
}
|
|
|
|
void pCanvas::onExpose(GdkEventExpose* expose) {
|
|
if(surface) gdk_draw_pixbuf(gtk_widget_get_window(gtkWidget), nullptr, surface, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
|
|
}
|
|
|
|
void pCanvas::rasterize() {
|
|
unsigned width = canvas.state.width;
|
|
unsigned height = canvas.state.height;
|
|
if(width == 0) width = widget.state.geometry.width;
|
|
if(height == 0) height = widget.state.geometry.height;
|
|
|
|
if(width != surfaceWidth || height != surfaceHeight) release();
|
|
surfaceWidth = width;
|
|
surfaceHeight = height;
|
|
|
|
if(width == 0 || height == 0) return;
|
|
|
|
if(!surface) surface = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height);
|
|
uint32_t* buffer = (uint32_t*)gdk_pixbuf_get_pixels(surface);
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Color) {
|
|
uint32_t color = canvas.state.color.argb();
|
|
for(unsigned n = 0; n < width * height; n++) buffer[n] = color;
|
|
}
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Gradient) {
|
|
nall::image image;
|
|
image.allocate(width, height);
|
|
image.gradient(
|
|
canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb()
|
|
);
|
|
memcpy(buffer, image.data, image.size);
|
|
}
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Image) {
|
|
nall::image image = canvas.state.image;
|
|
image.scale(width, height);
|
|
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
|
|
memcpy(buffer, image.data, image.size);
|
|
}
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Data) {
|
|
if(width == canvas.state.width && height == canvas.state.height) {
|
|
memcpy(buffer, canvas.state.data, width * height * sizeof(uint32_t));
|
|
} else {
|
|
memset(buffer, 0x00, width * height * sizeof(uint32_t));
|
|
}
|
|
}
|
|
|
|
//ARGB -> ABGR conversion
|
|
for(unsigned n = 0; n < width * height; n++) {
|
|
uint32_t color = *buffer;
|
|
color = (color & 0xff00ff00) | ((color & 0xff0000) >> 16) | ((color & 0x0000ff) << 16);
|
|
*buffer++ = color;
|
|
}
|
|
}
|
|
|
|
void pCanvas::redraw() {
|
|
if(gtk_widget_get_realized(gtkWidget)) {
|
|
gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), nullptr, true);
|
|
}
|
|
}
|
|
|
|
void pCanvas::release() {
|
|
if(surface == nullptr) return;
|
|
g_object_unref(surface);
|
|
surface = nullptr;
|
|
surfaceWidth = 0;
|
|
surfaceHeight = 0;
|
|
}
|
|
|
|
}
|