2252 lines
65 KiB
C
2252 lines
65 KiB
C
#include <errno.h>
|
|
#include <sys/fswait.h>
|
|
#include <toaru/yutani.h>
|
|
#include <toaru/decorations.h>
|
|
#include <toaru/menu.h>
|
|
#include <toaru/text.h>
|
|
#include <toaru/button.h>
|
|
|
|
#include <kuroko/kuroko.h>
|
|
#include <kuroko/vm.h>
|
|
#include <kuroko/util.h>
|
|
|
|
static KrkInstance * _module;
|
|
|
|
#define CURRENT_NAME self
|
|
|
|
#define WRAP_TYPE(kname,yname,pname,...) \
|
|
static KrkClass * kname; \
|
|
struct _yutani_ ## kname { \
|
|
KrkInstance inst; \
|
|
yname * pname; \
|
|
__VA_ARGS__ \
|
|
}; \
|
|
__attribute__((unused)) \
|
|
static int _init_check_ ## kname (struct _yutani_ ## kname * self) { \
|
|
return self->pname != NULL; \
|
|
}
|
|
|
|
#define NO_REINIT(type) do { if (_init_check_ ## type (self)) return krk_runtimeError(vm.exceptions->typeError, "Can not reinit " #type); } while (0)
|
|
#define INIT_CHECK(type) do { if (!_init_check_ ## type (self)) return krk_runtimeError(vm.exceptions->typeError, #type " object uninitialized"); } while (0)
|
|
|
|
WRAP_TYPE(Message,yutani_msg_t,msg);
|
|
#define IS_Message(o) (krk_isInstanceOf(o,Message))
|
|
#define AS_Message(o) ((struct _yutani_Message*)AS_OBJECT(o))
|
|
static void _Message_gcsweep(KrkInstance * _self) {
|
|
struct _yutani_Message * self = (void*)_self;
|
|
free(self->msg);
|
|
}
|
|
|
|
#define CURRENT_CTYPE struct _yutani_Message*
|
|
|
|
KRK_StaticMethod(Message,__new__) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "can not instantiate Message");
|
|
}
|
|
|
|
/* Base type stuff */
|
|
KRK_Method(Message,msg_magic) {
|
|
ATTRIBUTE_NOT_ASSIGNABLE();
|
|
return INTEGER_VAL(self->msg->magic);
|
|
}
|
|
|
|
KRK_Method(Message,msg_type) {
|
|
ATTRIBUTE_NOT_ASSIGNABLE();
|
|
return INTEGER_VAL(self->msg->type);
|
|
}
|
|
|
|
KRK_Method(Message,msg_size) {
|
|
ATTRIBUTE_NOT_ASSIGNABLE();
|
|
return INTEGER_VAL(self->msg->size);
|
|
}
|
|
|
|
KRK_Method(Message,__repr__) {
|
|
struct StringBuilder sb = {0};
|
|
|
|
pushStringBuilder(&sb,'<');
|
|
|
|
const char * typeName = krk_typeName(argv[0]);
|
|
pushStringBuilderStr(&sb, typeName, strlen(typeName));
|
|
|
|
pushStringBuilder(&sb, '>');
|
|
return finishStringBuilder(&sb);
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
/* Subclass stuff */
|
|
#define MSG_CLS(type) Message_ ## type
|
|
#define WRAP_PROP_INT(cls,kname) KRK_Method(cls,kname) { return INTEGER_VAL(self->kname); }
|
|
#define WRAP_PROP_BOOL(cls,kname) KRK_Method(cls,kname) { return BOOLEAN_VAL(self->kname); }
|
|
|
|
static KrkClass * MSG_CLS(Welcome);
|
|
#define AS_Message_Welcome(o) ((struct yutani_msg_welcome*)AS_Message(o)->msg->data)
|
|
#define IS_Message_Welcome(o) (krk_isInstanceOf(o,MSG_CLS(Welcome)))
|
|
#define CURRENT_CTYPE struct yutani_msg_welcome *
|
|
WRAP_PROP_INT(Message_Welcome,display_width)
|
|
WRAP_PROP_INT(Message_Welcome,display_height)
|
|
#undef CURRENT_CTYPE
|
|
|
|
static KrkClass * MSG_CLS(WindowMouseEvent);
|
|
#define AS_Message_WindowMouseEvent(o) ((struct yutani_msg_window_mouse_event*)AS_Message(o)->msg->data)
|
|
#define IS_Message_WindowMouseEvent(o) (krk_isInstanceOf(o,MSG_CLS(WindowMouseEvent)))
|
|
#define CURRENT_CTYPE struct yutani_msg_window_mouse_event *
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,wid)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,new_x)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,new_y)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,old_x)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,old_y)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,buttons)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,command)
|
|
WRAP_PROP_INT(Message_WindowMouseEvent,modifiers)
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define AS_Message_WindowFocusChange(o) ((struct yutani_msg_window_focus_change*)AS_Message(o)->msg->data)
|
|
#define IS_Message_WindowFocusChange(o) (krk_isInstanceOf(o,MSG_CLS(WindowFocusChange)))
|
|
#define CURRENT_CTYPE struct yutani_msg_window_focus_change *
|
|
static KrkClass * MSG_CLS(WindowFocusChange);
|
|
WRAP_PROP_INT(Message_WindowFocusChange,wid)
|
|
WRAP_PROP_BOOL(Message_WindowFocusChange,focused)
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define AS_Message_ResizeOffer(o) ((struct yutani_msg_window_resize*)AS_Message(o)->msg->data)
|
|
#define IS_Message_ResizeOffer(o) (krk_isInstanceOf(o,MSG_CLS(ResizeOffer)))
|
|
#define CURRENT_CTYPE struct yutani_msg_window_resize *
|
|
static KrkClass * MSG_CLS(ResizeOffer);
|
|
WRAP_PROP_INT(Message_ResizeOffer,wid)
|
|
WRAP_PROP_INT(Message_ResizeOffer,width)
|
|
WRAP_PROP_INT(Message_ResizeOffer,height)
|
|
WRAP_PROP_INT(Message_ResizeOffer,bufid)
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define AS_Message_WindowAdvertise(o) ((struct yutani_msg_window_advertise*)AS_Message(o)->msg->data)
|
|
#define IS_Message_WindowAdvertise(o) (krk_isInstanceOf(o,MSG_CLS(WindowAdvertise)))
|
|
#define CURRENT_CTYPE struct yutani_msg_window_advertise *
|
|
static KrkClass * MSG_CLS(WindowAdvertise);
|
|
WRAP_PROP_INT(Message_WindowAdvertise,wid)
|
|
WRAP_PROP_INT(Message_WindowAdvertise,flags)
|
|
WRAP_PROP_INT(Message_WindowAdvertise,size)
|
|
WRAP_PROP_INT(Message_WindowAdvertise,width)
|
|
WRAP_PROP_INT(Message_WindowAdvertise,height)
|
|
WRAP_PROP_INT(Message_WindowAdvertise,bufid)
|
|
KRK_Method(Message_WindowAdvertise,name) {
|
|
char * s = self->strings;
|
|
size_t l = strlen(s);
|
|
return OBJECT_VAL(krk_copyString(s,l));
|
|
}
|
|
KRK_Method(Message_WindowAdvertise,icon) {
|
|
char * s = self->strings + self->icon;
|
|
size_t l = strlen(s);
|
|
return OBJECT_VAL(krk_copyString(s,l));
|
|
}
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define AS_Message_WindowMove(o) ((struct yutani_msg_window_move*)AS_Message(o)->msg->data)
|
|
#define IS_Message_WindowMove(o) (krk_isInstanceOf(o,MSG_CLS(WindowMove)))
|
|
#define CURRENT_CTYPE struct yutani_msg_window_move *
|
|
static KrkClass * MSG_CLS(WindowMove);
|
|
WRAP_PROP_INT(Message_WindowMove,wid)
|
|
WRAP_PROP_INT(Message_WindowMove,x)
|
|
WRAP_PROP_INT(Message_WindowMove,y)
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define AS_Message_KeyEvent(o) ((struct yutani_msg_key_event*)AS_Message(o)->msg->data)
|
|
#define IS_Message_KeyEvent(o) (krk_isInstanceOf(o,MSG_CLS(KeyEvent)))
|
|
#define CURRENT_CTYPE struct yutani_msg_key_event *
|
|
static KrkClass * MSG_CLS(KeyEvent);
|
|
WRAP_PROP_INT(Message_KeyEvent,wid)
|
|
|
|
#define WRAP_PROP_FROM(f,p) KRK_Method(Message_KeyEvent,p) { return INTEGER_VAL(self->f.p); }
|
|
WRAP_PROP_FROM(event,keycode)
|
|
WRAP_PROP_FROM(event,modifiers)
|
|
WRAP_PROP_FROM(event,action)
|
|
WRAP_PROP_FROM(event,key)
|
|
WRAP_PROP_FROM(state,kbd_state)
|
|
WRAP_PROP_FROM(state,kbd_s_state)
|
|
WRAP_PROP_FROM(state,k_ctrl)
|
|
WRAP_PROP_FROM(state,k_shift)
|
|
WRAP_PROP_FROM(state,k_alt)
|
|
WRAP_PROP_FROM(state,k_super)
|
|
WRAP_PROP_FROM(state,kl_ctrl)
|
|
WRAP_PROP_FROM(state,kl_shift)
|
|
WRAP_PROP_FROM(state,kl_alt)
|
|
WRAP_PROP_FROM(state,kl_super)
|
|
WRAP_PROP_FROM(state,kr_ctrl)
|
|
WRAP_PROP_FROM(state,kr_shift)
|
|
WRAP_PROP_FROM(state,kr_alt)
|
|
WRAP_PROP_FROM(state,kr_super)
|
|
WRAP_PROP_FROM(state,kbd_esc_buf)
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define AS_Message_WindowClose(o) ((struct yutani_msg_key_event*)AS_Message(o)->msg->data)
|
|
#define IS_Message_WindowClose(o) (krk_isInstanceOf(o,MSG_CLS(WindowClose)))
|
|
#define CURRENT_CTYPE struct yutani_msg_key_event *
|
|
static KrkClass * MSG_CLS(WindowClose);
|
|
WRAP_PROP_INT(Message_WindowClose,wid)
|
|
#undef CURRENT_CTYPE
|
|
|
|
WRAP_TYPE(YutaniCtx,yutani_t,yctx);
|
|
#define AS_YutaniCtx(o) ((struct _yutani_YutaniCtx*)AS_OBJECT(o))
|
|
#define IS_YutaniCtx(o) (krk_isInstanceOf(o,YutaniCtx))
|
|
#define CURRENT_CTYPE struct _yutani_YutaniCtx*
|
|
|
|
static struct _yutani_YutaniCtx * yctxInstance;
|
|
KRK_StaticMethod(YutaniCtx,__new__) {
|
|
if (yctxInstance) return OBJECT_VAL(yctxInstance);
|
|
|
|
KrkClass * cls;
|
|
if (!krk_parseArgs("O!:YutaniCtx", (const char*[]){"cls"}, KRK_BASE_CLASS(type), &cls)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)krk_newInstance(cls);
|
|
krk_push(OBJECT_VAL(self));
|
|
|
|
yutani_t * yctx = yutani_init();
|
|
if (!yctx) return krk_runtimeError(vm.exceptions->ioError, "Failed to connect to compositor.");
|
|
yctxInstance = self;
|
|
self->yctx = yctx;
|
|
init_decorations();
|
|
krk_attachNamedObject(&_module->fields, "_yutani_t", (KrkObj*)self);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,display_width) { return INTEGER_VAL(self->yctx->display_width); }
|
|
KRK_Method(YutaniCtx,display_height) { return INTEGER_VAL(self->yctx->display_height); }
|
|
|
|
static KrkValue makeMessage(yutani_msg_t * result) {
|
|
if (!result) return NONE_VAL();
|
|
|
|
KrkClass * msgType = Message;
|
|
switch (result->type) {
|
|
case YUTANI_MSG_WELCOME:
|
|
msgType = Message_Welcome;
|
|
break;
|
|
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
|
msgType = Message_WindowMouseEvent;
|
|
break;
|
|
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
|
msgType = Message_WindowFocusChange;
|
|
break;
|
|
case YUTANI_MSG_RESIZE_OFFER:
|
|
msgType = Message_ResizeOffer;
|
|
break;
|
|
case YUTANI_MSG_WINDOW_ADVERTISE:
|
|
msgType = Message_WindowAdvertise;
|
|
break;
|
|
case YUTANI_MSG_WINDOW_MOVE:
|
|
msgType = Message_WindowMove;
|
|
break;
|
|
case YUTANI_MSG_KEY_EVENT:
|
|
msgType = Message_KeyEvent;
|
|
break;
|
|
case YUTANI_MSG_WINDOW_CLOSE:
|
|
msgType = Message_WindowClose;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
struct _yutani_Message * out = (void*)krk_newInstance(msgType);
|
|
out->msg = result;
|
|
return OBJECT_VAL(out);
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,poll) {
|
|
int sync = 1;
|
|
|
|
if (!krk_parseArgs(".|p", (const char *[]){"sync"}, &sync)) return NONE_VAL();
|
|
|
|
yutani_msg_t * result = sync ? yutani_poll(self->yctx) : yutani_poll_async(self->yctx);
|
|
|
|
return makeMessage(result);
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,wait_for) {
|
|
int msgtype;
|
|
if (!krk_parseArgs(".i",(const char*[]){"msgtype"}, &msgtype)) return NONE_VAL();
|
|
yutani_msg_t * result = yutani_wait_for(self->yctx, msgtype);
|
|
return makeMessage(result);
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,subscribe) {
|
|
yutani_subscribe_windows(self->yctx);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,unsubscribe) {
|
|
yutani_unsubscribe_windows(self->yctx);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,query_windows) {
|
|
yutani_query_windows(self->yctx);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,fileno) {
|
|
return INTEGER_VAL(fileno(self->yctx->sock));
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,query) {
|
|
return INTEGER_VAL(yutani_query(self->yctx));
|
|
}
|
|
|
|
KRK_Method(YutaniCtx,menu_process_event) {
|
|
struct _yutani_Message * message = NULL;
|
|
if (!krk_parseArgs(".O!",(const char *[]){"message"}, Message, &message)) return NONE_VAL();
|
|
return INTEGER_VAL(menu_process_event(self->yctx, message->msg));
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
WRAP_TYPE(GraphicsContext,gfx_context_t,ctx,
|
|
int doubleBuffered;
|
|
);
|
|
|
|
WRAP_TYPE(Sprite,gfx_context_t,ctx,
|
|
int doubleBuffered;
|
|
sprite_t * sprite;
|
|
);
|
|
|
|
WRAP_TYPE(Window,gfx_context_t,ctx,
|
|
int doubleBuffered;
|
|
yutani_window_t * window;
|
|
KrkValue title;
|
|
KrkValue icon;
|
|
int closed;
|
|
);
|
|
|
|
WRAP_TYPE(Subregion,gfx_context_t,ctx,
|
|
int doubleBuffered;
|
|
int x;
|
|
int y;
|
|
);
|
|
|
|
#define IS_GraphicsContext(o) (krk_isInstanceOf(o,GraphicsContext))
|
|
#define AS_GraphicsContext(o) ((struct _yutani_GraphicsContext*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_GraphicsContext*
|
|
|
|
#define CHECK_GFX() do { if (!self->ctx) return krk_runtimeError(vm.exceptions->valueError, "invalid context"); } while (0)
|
|
|
|
KRK_StaticMethod(GraphicsContext,__new__) {
|
|
KrkClass * cls;
|
|
int _argc;
|
|
const KrkValue * _argv;
|
|
|
|
if (!krk_parseArgs("O!*~",(const char*[]){"cls"},KRK_BASE_CLASS(type),&cls,&_argc,&_argv)) return NONE_VAL();
|
|
|
|
if (!krk_isSubClass(cls, GraphicsContext)) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "%S is not a subclass of GraphicsContext", cls->name);
|
|
}
|
|
|
|
if (cls == GraphicsContext) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "Can not create GraphicsContext");
|
|
}
|
|
|
|
return OBJECT_VAL(krk_newInstance(cls));
|
|
}
|
|
|
|
KRK_Method(GraphicsContext,fill) {
|
|
uint32_t color;
|
|
if (!krk_parseArgs(".I",(const char*[]){"color"},&color)) return NONE_VAL();
|
|
CHECK_GFX();
|
|
draw_fill(self->ctx, color);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(GraphicsContext,flip) {
|
|
CHECK_GFX();
|
|
if (self->doubleBuffered) {
|
|
flip(self->ctx);
|
|
}
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(GraphicsContext,blur) {
|
|
int radius = 2;
|
|
if (!krk_parseArgs(".|I",(const char*[]){"radius"}, &radius)) return NONE_VAL();
|
|
CHECK_GFX();
|
|
blur_context_box(self->ctx, radius);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(GraphicsContext,line) {
|
|
int x0, x1, y0, y1;
|
|
uint32_t color;
|
|
KrkValue thickness = NONE_VAL();
|
|
|
|
if (!krk_parseArgs(".iiiiI|V",(const char*[]){"x0","x1","y0","y1","color","thickness"},
|
|
&x0, &x1, &y0, &y1, &color, &thickness)) return NONE_VAL();
|
|
|
|
if (IS_NONE(thickness)) {
|
|
draw_line(self->ctx, x0, x1, y0, y1, color);
|
|
} else if (IS_INTEGER(thickness)) {
|
|
draw_line_thick(self->ctx, x0, x1, y0, y1, color, AS_INTEGER(thickness));
|
|
} else if (IS_FLOATING(thickness)) {
|
|
draw_line_aa(self->ctx, x0, x1, y0, y1, color, AS_FLOATING(thickness));
|
|
} else {
|
|
TYPE_ERROR(int or float,thickness);
|
|
}
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(GraphicsContext,rect) {
|
|
int x, y;
|
|
unsigned int width, height;
|
|
uint32_t color;
|
|
int solid = 0;
|
|
unsigned int radius = 0;
|
|
|
|
if (!krk_parseArgs(".iiIII|pI",(const char*[]){"x","y","width","height","color","solid","radius"},
|
|
&x, &y, &width, &height, &color, &solid, &radius)) return NONE_VAL();
|
|
|
|
if (solid && radius) {
|
|
return krk_runtimeError(vm.exceptions->valueError, "can not combine 'radius' and 'solid'");
|
|
}
|
|
|
|
CHECK_GFX();
|
|
|
|
if (radius) {
|
|
draw_rounded_rectangle(self->ctx, x, y, width, height, radius, color);
|
|
} else if (solid) {
|
|
draw_rectangle_solid(self->ctx, x, y, width, height, color);
|
|
} else {
|
|
draw_rectangle(self->ctx, x, y, width, height, color);
|
|
}
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(GraphicsContext,width) { CHECK_GFX(); return INTEGER_VAL(self->ctx->width); }
|
|
KRK_Method(GraphicsContext,height) { CHECK_GFX(); return INTEGER_VAL(self->ctx->height); }
|
|
KRK_Method(GraphicsContext,isDoubleBuffered) { CHECK_GFX(); return BOOLEAN_VAL(self->doubleBuffered); }
|
|
|
|
KRK_Method(GraphicsContext,draw_sprite) {
|
|
CHECK_GFX();
|
|
|
|
struct _yutani_Sprite * sprite;
|
|
int x = 0;
|
|
int y = 0;
|
|
double alpha = 1.0;
|
|
double rotation = 0.0;
|
|
KrkTuple * scale = NULL;
|
|
uint32_t color = 0;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!|iiddO!I",(const char*[]){"sprite","x","y","alpha","rotation","scale","color"},
|
|
Sprite, &sprite,
|
|
&x, &y,
|
|
&alpha, &rotation,
|
|
KRK_BASE_CLASS(tuple), &scale,
|
|
&color)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
if (scale) {
|
|
if (scale->values.count != 2 || !IS_INTEGER(scale->values.values[0]) || !IS_INTEGER(scale->values.values[1])) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "scale must be (int,int)");
|
|
}
|
|
|
|
int32_t width = AS_INTEGER(scale->values.values[0]);
|
|
int32_t height = AS_INTEGER(scale->values.values[1]);
|
|
|
|
if (alpha == 1.0) {
|
|
draw_sprite_scaled(self->ctx, sprite->sprite, x, y, width, height);
|
|
} else {
|
|
draw_sprite_scaled_alpha(self->ctx, sprite->sprite, x, y, width, height, alpha);
|
|
}
|
|
} else if (color) {
|
|
draw_sprite_alpha_paint(self->ctx, sprite->sprite, x, y, alpha, color);
|
|
} else if (rotation != 0.0) {
|
|
draw_sprite_rotate(self->ctx, sprite->sprite, x, y, rotation, alpha);
|
|
} else if (alpha == 1.0) {
|
|
draw_sprite(self->ctx, sprite->sprite, x, y);
|
|
} else {
|
|
draw_sprite_alpha(self->ctx, sprite->sprite, x, y, alpha);
|
|
}
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
static void _yutani_Sprite_gcsweep(KrkInstance * _self) {
|
|
struct _yutani_Sprite * self = (void*)_self;
|
|
if (self->sprite) sprite_free(self->sprite);
|
|
if (self->ctx) release_graphics_yutani(self->ctx);
|
|
}
|
|
|
|
#define IS_Sprite(o) (krk_isInstanceOf(o,Sprite))
|
|
#define AS_Sprite(o) ((struct _yutani_Sprite*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_Sprite*
|
|
|
|
/**
|
|
* Sprite(file=None,*,width=0,height=0)
|
|
*
|
|
* Either file or width/height need to be specified, but not both.
|
|
*/
|
|
KRK_Method(Sprite,__init__) {
|
|
const char * filename = NULL;
|
|
unsigned int width = 0;
|
|
unsigned int height = 0;
|
|
|
|
if (!krk_parseArgs(
|
|
".|z$II:Sprite",(const char*[]){"file","width","height"},
|
|
&filename,
|
|
&width,
|
|
&height
|
|
)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
if ((!filename && (!width || !height)) || (filename && (width || height))) {
|
|
return krk_runtimeError(vm.exceptions->argumentError,
|
|
"Either 'file' or both of 'width' and 'height' must be provided, but not both.");
|
|
}
|
|
|
|
NO_REINIT(Sprite);
|
|
|
|
sprite_t * sprite;
|
|
|
|
/* Set up sprite */
|
|
if (!filename) {
|
|
/* Want to build a new sprite */
|
|
sprite = create_sprite(width, height, ALPHA_EMBEDDED);
|
|
} else {
|
|
sprite = malloc(sizeof(sprite_t));
|
|
if (load_sprite(sprite, filename)) {
|
|
free(sprite);
|
|
return krk_runtimeError(vm.exceptions->ioError, "could not load sprite from '%s'", filename);
|
|
}
|
|
}
|
|
|
|
/* Initialize representative graphics context */
|
|
gfx_context_t * ctx = init_graphics_sprite(sprite);
|
|
|
|
self->ctx = ctx;
|
|
self->sprite = sprite;
|
|
|
|
/* Keep the file if we had one */
|
|
krk_attachNamedValue(&self->inst.fields, "file",
|
|
filename ? OBJECT_VAL(krk_copyString(filename,strlen(filename))) : NONE_VAL());
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Sprite,__repr__) {
|
|
KrkValue file = NONE_VAL();
|
|
krk_tableGet_fast(&self->inst.fields, S("file"), &file);
|
|
|
|
INIT_CHECK(Sprite);
|
|
|
|
if (!IS_NONE(file)) {
|
|
return krk_stringFromFormat("Sprite(file=%R,width=%u,height=%u)",
|
|
file, self->sprite->width, self->sprite->height);
|
|
} else {
|
|
return krk_stringFromFormat("Sprite(width=%u,height=%u)",
|
|
self->sprite->width, self->sprite->height);
|
|
}
|
|
}
|
|
|
|
KRK_Method(Sprite,free) {
|
|
INIT_CHECK(Sprite);
|
|
if (self->sprite) sprite_free(self->sprite);
|
|
if (self->ctx) release_graphics_yutani(self->ctx);
|
|
self->sprite = NULL;
|
|
self->ctx = NULL;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
static void _yutani_Window_gcscan(KrkInstance * _self) {
|
|
struct _yutani_Window * self = (void*)_self;
|
|
krk_markValue(self->title);
|
|
krk_markValue(self->icon);
|
|
}
|
|
|
|
#define IS_Window(o) (krk_isInstanceOf(o,Window))
|
|
#define AS_Window(o) ((struct _yutani_Window*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_Window*
|
|
|
|
static void update_window_title(struct _yutani_Window * self) {
|
|
if (IS_STRING(self->title)) {
|
|
if (IS_STRING(self->icon)) {
|
|
yutani_window_advertise_icon(yctxInstance->yctx, self->window, AS_CSTRING(self->title), AS_CSTRING(self->icon));
|
|
} else {
|
|
yutani_window_advertise(yctxInstance->yctx, self->window, AS_CSTRING(self->title));
|
|
}
|
|
}
|
|
|
|
/* TODO Update decorations */
|
|
}
|
|
|
|
KRK_Method(Window,__init__) {
|
|
unsigned int width;
|
|
unsigned int height;
|
|
unsigned int flags = 0;
|
|
KrkValue title = NONE_VAL();
|
|
KrkValue icon = NONE_VAL();
|
|
int doublebuffer = 1;
|
|
|
|
if (!yctxInstance) return krk_runtimeError(vm.exceptions->valueError, "Compositor is not initialized");
|
|
|
|
if (!krk_parseArgs(
|
|
".II|IV!V!p:Window",(const char *[]){"width","height","flags","title","icon","doublebuffer"},
|
|
&width, &height,
|
|
&flags,
|
|
KRK_BASE_CLASS(str), &title,
|
|
KRK_BASE_CLASS(str), &icon,
|
|
&doublebuffer
|
|
)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
NO_REINIT(Window);
|
|
|
|
self->window = yutani_window_create_flags(yctxInstance->yctx, width, height, flags);
|
|
self->doubleBuffered = doublebuffer;
|
|
self->ctx = doublebuffer ? init_graphics_yutani_double_buffer(self->window) : init_graphics_yutani(self->window);
|
|
self->title = title;
|
|
self->icon = icon;
|
|
self->closed = 0;
|
|
|
|
update_window_title(self);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,title) {
|
|
INIT_CHECK(Window);
|
|
if (argc > 1) {
|
|
if (!IS_STRING(argv[1]) && !IS_NONE(argv[1])) return TYPE_ERROR(str,argv[1]);
|
|
self->title = argv[1];
|
|
update_window_title(self);
|
|
}
|
|
return self->title;
|
|
}
|
|
|
|
KRK_Method(Window,icon) {
|
|
INIT_CHECK(Window);
|
|
if (argc > 1) {
|
|
if (!IS_STRING(argv[1]) && !IS_NONE(argv[1])) return TYPE_ERROR(str,argv[1]);
|
|
self->icon = argv[1];
|
|
update_window_title(self);
|
|
}
|
|
|
|
return self->icon;
|
|
}
|
|
|
|
KRK_Method(Window,wid) { INIT_CHECK(Window); return INTEGER_VAL(self->window->wid); }
|
|
KRK_Method(Window,x) { INIT_CHECK(Window); return INTEGER_VAL(self->window->x); }
|
|
KRK_Method(Window,y) { INIT_CHECK(Window); return INTEGER_VAL(self->window->y); }
|
|
KRK_Method(Window,focused) {
|
|
INIT_CHECK(Window);
|
|
|
|
if (argc > 1) {
|
|
if (!IS_BOOLEAN(argv[1])) return krk_runtimeError(vm.exceptions->typeError, "focused must be bool, not %T", argv[1]);
|
|
self->window->focused = AS_BOOLEAN(argv[1]);
|
|
}
|
|
|
|
return BOOLEAN_VAL(self->window->focused);
|
|
}
|
|
|
|
KRK_Method(Window,closed) { return INTEGER_VAL(self->closed); }
|
|
|
|
KRK_Method(Window,__repr__) {
|
|
INIT_CHECK(Window);
|
|
if (!self->window) {
|
|
return krk_stringFromFormat("Window(title=%R,closed=True)", self->title);
|
|
}
|
|
return krk_stringFromFormat("Window(wid=%d,title=%R,width=%d,height=%d)",
|
|
self->window->wid, self->title, self->window->width, self->window->height);
|
|
}
|
|
|
|
KRK_Method(Window,flip) {
|
|
INIT_CHECK(Window);
|
|
if (self->doubleBuffered) {
|
|
flip(self->ctx);
|
|
}
|
|
yutani_flip(yctxInstance->yctx, self->window);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,move) {
|
|
int x, y;
|
|
if (!krk_parseArgs(".ii", (const char*[]){"x","y"}, &x, &y)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_move(yctxInstance->yctx, self->window, x, y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,close) {
|
|
INIT_CHECK(Window);
|
|
yutani_close(yctxInstance->yctx, self->window);
|
|
self->window = NULL;
|
|
release_graphics_yutani(self->ctx);
|
|
self->ctx = NULL;
|
|
self->closed = 1;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,set_stack) {
|
|
unsigned int z;
|
|
if (!krk_parseArgs(".I", (const char*[]){"z"}, &z)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_set_stack(yctxInstance->yctx, self->window, z);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,special_request) {
|
|
unsigned int request;
|
|
if (!krk_parseArgs(".I", (const char*[]){"request"}, &request)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_special_request(yctxInstance->yctx, self->window, request);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,resize) {
|
|
unsigned int width, height;
|
|
if (!krk_parseArgs(".II", (const char*[]){"width","height"}, &width, &height)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_resize(yctxInstance->yctx, self->window, width, height);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,resize_start) {
|
|
unsigned int direction;
|
|
if (!krk_parseArgs(".I", (const char*[]){"direction"}, &direction)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_resize_start(yctxInstance->yctx, self->window, direction);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,resize_done) {
|
|
INIT_CHECK(Window);
|
|
yutani_window_resize_done(yctxInstance->yctx, self->window);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,resize_offer) {
|
|
unsigned int width, height;
|
|
if (!krk_parseArgs(".II", (const char*[]){"width","height"}, &width, &height)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_resize_offer(yctxInstance->yctx, self->window, width, height);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,resize_accept) {
|
|
unsigned int width, height;
|
|
if (!krk_parseArgs(".II", (const char*[]){"width","height"}, &width, &height)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_resize_accept(yctxInstance->yctx, self->window, width, height);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,update_shape) {
|
|
unsigned int threshold;
|
|
if (!krk_parseArgs(".I", (const char*[]){"threshold"}, &threshold)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_update_shape(yctxInstance->yctx, self->window, threshold);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,show_mouse) {
|
|
unsigned int mouse;
|
|
if (!krk_parseArgs(".I", (const char*[]){"mouse"}, &mouse)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_show_mouse(yctxInstance->yctx, self->window, mouse);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,warp_mouse) {
|
|
int x, y;
|
|
if (!krk_parseArgs(".ii", (const char*[]){"x","y"}, &x, &y)) return NONE_VAL();
|
|
INIT_CHECK(Window);
|
|
yutani_window_warp_mouse(yctxInstance->yctx, self->window, x, y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Window,reinit) {
|
|
INIT_CHECK(Window);
|
|
reinit_graphics_yutani(self->ctx, self->window);
|
|
return NONE_VAL();
|
|
}
|
|
#undef CURRENT_CTYPE
|
|
|
|
static void _yutani_Subregion_gcsweep(KrkInstance * _self) {
|
|
struct _yutani_Subregion * self = (void*)_self;
|
|
if (self->ctx) {
|
|
if (self->ctx->clips) {
|
|
free(self->ctx->clips);
|
|
}
|
|
free(self->ctx);
|
|
self->ctx = NULL;
|
|
}
|
|
}
|
|
|
|
#define IS_Subregion(o) (krk_isInstanceOf(o,Subregion))
|
|
#define AS_Subregion(o) ((struct _yutani_Subregion*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_Subregion*
|
|
|
|
KRK_Method(Subregion,__init__) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
int x, y, w, h;
|
|
if (!krk_parseArgs(
|
|
".O!iiii:Subregion", (const char*[]){"ctx","x","y","w","h"},
|
|
GraphicsContext, &ctx,
|
|
&x, &y, &w, &h)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
NO_REINIT(Subregion);
|
|
|
|
if (!ctx->ctx) return krk_runtimeError(vm.exceptions->typeError, "ctx is not initialized");
|
|
|
|
if (w < 0 || h < 0) return krk_runtimeError(vm.exceptions->typeError, "invalid subregion");
|
|
|
|
if (x < 0) {
|
|
w += x;
|
|
x = 0;
|
|
}
|
|
|
|
if (y < 0) {
|
|
h += y;
|
|
y = 0;
|
|
}
|
|
|
|
if (x >= ctx->ctx->width || y >= ctx->ctx->height) {
|
|
x = 0; y = 0; w = 0; h = 0;
|
|
}
|
|
|
|
if (x + w > ctx->ctx->width) {
|
|
w = ctx->ctx->width - x;
|
|
}
|
|
|
|
if (y + h > ctx->ctx->height) {
|
|
h = ctx->ctx->height - y;
|
|
}
|
|
|
|
gfx_context_t * sub = init_graphics_subregion(ctx->ctx, x, y, w, h);
|
|
self->ctx = sub;
|
|
self->doubleBuffered = ctx->doubleBuffered;
|
|
self->x = x;
|
|
self->y = y;
|
|
krk_attachNamedObject(&self->inst.fields, "parent", (KrkObj*)ctx);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Subregion,offset_x) {
|
|
ATTRIBUTE_NOT_ASSIGNABLE();
|
|
return INTEGER_VAL(self->x);
|
|
}
|
|
|
|
KRK_Method(Subregion,offset_y) {
|
|
ATTRIBUTE_NOT_ASSIGNABLE();
|
|
return INTEGER_VAL(self->y);
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
static KrkClass * TransformMatrix;
|
|
struct _yutani_TransformMatrix {
|
|
KrkInstance inst;
|
|
gfx_matrix_t matrix;
|
|
};
|
|
|
|
#define IS_TransformMatrix(o) (krk_isInstanceOf(o,TransformMatrix))
|
|
#define AS_TransformMatrix(o) ((struct _yutani_TransformMatrix*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_TransformMatrix*
|
|
|
|
KRK_Method(TransformMatrix,__init__) {
|
|
double a = 1.0, b = 0, tx = 0, c = 0, d = 1.0, ty = 0;
|
|
if (!krk_parseArgs(".|dddddd:TransformMatrix",
|
|
(const char*[]){"a","b","tx","c","d","ty"},
|
|
&a,&b,&tx,&c,&d,&ty)) return NONE_VAL();
|
|
self->matrix[0][0] = a;
|
|
self->matrix[0][1] = b;
|
|
self->matrix[0][2] = tx;
|
|
self->matrix[1][0] = c;
|
|
self->matrix[1][1] = d;
|
|
self->matrix[1][2] = ty;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#define MATRIX_VAR(name,row,col) KRK_Method(TransformMatrix,name) { \
|
|
double x = self->matrix[row][col]; \
|
|
if (!krk_parseArgs(".|d",(const char*[]){"val"},&x)) return NONE_VAL(); \
|
|
self->matrix[row][col] = x; \
|
|
return FLOATING_VAL(x); \
|
|
}
|
|
|
|
MATRIX_VAR(a,0,0)
|
|
MATRIX_VAR(b,0,1)
|
|
MATRIX_VAR(tx,0,1)
|
|
MATRIX_VAR(c,1,0)
|
|
MATRIX_VAR(d,1,1)
|
|
MATRIX_VAR(ty,1,1)
|
|
|
|
KRK_Method(TransformMatrix,__repr__) {
|
|
struct StringBuilder sb = {};
|
|
|
|
KrkValue floats[6];
|
|
|
|
for (int i = 0; i < 6; ++i) {
|
|
floats[i] = FLOATING_VAL(self->matrix[i/3][i%3]);
|
|
}
|
|
|
|
krk_pushStringBuilderFormat(&sb, "TransformMatrix[ [%R,%R,%R] [%R,%R,%R] ]",
|
|
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]);
|
|
|
|
return krk_finishStringBuilder(&sb);
|
|
}
|
|
|
|
KRK_Method(TransformMatrix,scale) {
|
|
double x, y;
|
|
if (!krk_parseArgs(".dd", (const char*[]){"x","y"}, &x, &y)) return NONE_VAL();
|
|
gfx_matrix_scale(self->matrix,x,y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TransformMatrix,translate) {
|
|
double x, y;
|
|
if (!krk_parseArgs(".dd", (const char*[]){"x","y"}, &x, &y)) return NONE_VAL();
|
|
gfx_matrix_translate(self->matrix,x,y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TransformMatrix,rotate) {
|
|
double r;
|
|
if (!krk_parseArgs(".d", (const char*[]){"r"}, &r)) return NONE_VAL();
|
|
gfx_matrix_rotate(self->matrix,r);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TransformMatrix,shear) {
|
|
double x, y;
|
|
if (!krk_parseArgs(".dd", (const char*[]){"x","y"}, &x, &y)) return NONE_VAL();
|
|
gfx_matrix_shear(self->matrix,x,y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TransformMatrix,apply) {
|
|
double x, y;
|
|
if (!krk_parseArgs(".dd", (const char*[]){"x","y"}, &x, &y)) return NONE_VAL();
|
|
KrkTuple * out = krk_newTuple(2);
|
|
krk_push(OBJECT_VAL(out));
|
|
|
|
double o_x, o_y;
|
|
gfx_apply_matrix(x,y,self->matrix,&o_x,&o_y);
|
|
out->values.values[out->values.count++] = FLOATING_VAL(o_x);
|
|
out->values.values[out->values.count++] = FLOATING_VAL(o_y);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
WRAP_TYPE(Font,struct TT_Font,fontData,
|
|
int fontSize;
|
|
uint32_t fontColor;
|
|
);
|
|
|
|
#define IS_Font(o) (krk_isInstanceOf(o,Font))
|
|
#define AS_Font(o) ((struct _yutani_Font*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_Font*
|
|
|
|
WRAP_TYPE(TTShape,struct TT_Shape, shape);
|
|
#define IS_TTShape(o) (krk_isInstanceOf(o,TTShape))
|
|
#define AS_TTShape(o) ((struct _yutani_TTShape*)AS_OBJECT(o))
|
|
|
|
WRAP_TYPE(TTContour,struct TT_Contour, contour);
|
|
#define IS_TTContour(o) (krk_isInstanceOf(o,TTContour))
|
|
#define AS_TTContour(o) ((struct _yutani_TTContour*)AS_OBJECT(o))
|
|
|
|
#define CHECK_FONT() do { if (!self->fontData) return krk_runtimeError(vm.exceptions->valueError, "font is uninitialized"); } while (0)
|
|
|
|
static void _yutani_Font_gcsweep(KrkInstance * _self) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self;
|
|
if (self->fontData) free(self->fontData);
|
|
}
|
|
|
|
KRK_Method(Font,__init__) {
|
|
const char * filename;
|
|
int size;
|
|
uint32_t color = rgb(0,0,0);
|
|
|
|
if (!krk_parseArgs(
|
|
".si|I:Font",(const char*[]){"font","size","color"},
|
|
&filename, &size, &color)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
NO_REINIT(Font);
|
|
|
|
struct TT_Font * fd;
|
|
|
|
if (strstr(filename, "sans-serif") == filename || strstr(filename, "monospace") == filename) {
|
|
fd = tt_font_from_shm(filename);
|
|
} else {
|
|
fd = tt_font_from_file(filename);
|
|
}
|
|
|
|
if (!fd) {
|
|
return krk_runtimeError(vm.exceptions->ioError, "failed to load '%s'", filename);
|
|
}
|
|
|
|
tt_set_size(fd, size);
|
|
|
|
self->fontData = fd;
|
|
self->fontSize = size;
|
|
self->fontColor = color;
|
|
|
|
krk_attachNamedValue(&self->inst.fields, "file", OBJECT_VAL(krk_copyString(filename, strlen(filename))));
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Font,size) {
|
|
INIT_CHECK(Font);
|
|
if (argc > 1) {
|
|
if (!IS_INTEGER(argv[1])) return krk_runtimeError(vm.exceptions->typeError, "size must be int, not %T", argv[1]);
|
|
self->fontSize = AS_INTEGER(argv[1]);
|
|
tt_set_size(self->fontData, self->fontSize);
|
|
}
|
|
|
|
return self->fontSize;
|
|
}
|
|
|
|
KRK_Method(Font,draw_string) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
const char * s;
|
|
int x;
|
|
int y;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!sii", (const char*[]){"ctx","s","x","y"},
|
|
GraphicsContext, &ctx,
|
|
&s, &x, &y)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(Font);
|
|
return INTEGER_VAL(tt_draw_string(ctx->ctx, self->fontData, x, y, s, self->fontColor));
|
|
}
|
|
|
|
KRK_Method(Font,draw_string_shadow) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
const char * s;
|
|
int x;
|
|
int y;
|
|
uint32_t shadow;
|
|
int blur;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!siiIi", (const char*[]){"ctx","s","x","y","shadow","blur"},
|
|
GraphicsContext, &ctx,
|
|
&s, &x, &y, &shadow, &blur)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(Font);
|
|
|
|
/* This has a weird API for reasons I can't remember */
|
|
tt_draw_string_shadow(ctx->ctx, self->fontData, (char*)s, self->fontSize, x, y, self->fontColor, shadow, blur);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Font,width) {
|
|
const char * s;
|
|
if (!krk_parseArgs(".s", (const char*[]){"s"}, &s)) return NONE_VAL();
|
|
INIT_CHECK(Font);
|
|
return INTEGER_VAL(tt_string_width(self->fontData, s));
|
|
}
|
|
|
|
KRK_Method(Font,measure) {
|
|
INIT_CHECK(Font);
|
|
|
|
KrkTuple * out = krk_newTuple(3);
|
|
krk_push(OBJECT_VAL(out));
|
|
|
|
struct TT_FontMetrics metrics;
|
|
|
|
tt_measure_font(self->fontData, &metrics);
|
|
|
|
out->values.values[out->values.count++] = FLOATING_VAL(metrics.ascender);
|
|
out->values.values[out->values.count++] = FLOATING_VAL(metrics.descender);
|
|
out->values.values[out->values.count++] = FLOATING_VAL(metrics.lineGap);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
KRK_Method(Font,draw_glyph_into) {
|
|
INIT_CHECK(Font);
|
|
|
|
struct _yutani_TTContour * contour;
|
|
float x, y;
|
|
unsigned int glyph;
|
|
|
|
if (!krk_parseArgs(".O!ffI",
|
|
(const char*[]){"contour","x","y","glyph"},
|
|
TTContour, &contour,
|
|
&x, &y, &glyph)) return NONE_VAL();
|
|
|
|
if (!contour->contour) return krk_runtimeError(vm.exceptions->typeError, "contour is not initialized");
|
|
|
|
/* tt_draw_glyph_into returns potentially-realloc'd contour, but we'll return nothing and
|
|
* just mutate the passed contour object. */
|
|
contour->contour = tt_draw_glyph_into(contour->contour, self->fontData, x, y, glyph);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(Font,prepare_string) {
|
|
INIT_CHECK(Font);
|
|
|
|
struct _yutani_TTContour * contour = NULL;
|
|
float x, y;
|
|
const char * s;
|
|
|
|
if (!krk_parseArgs(".ffs|O!", (const char*[]){"x","y","s","into"},
|
|
&x, &y, &s, TTContour, &contour)) return NONE_VAL();
|
|
|
|
float out_width = 0;
|
|
KrkTuple * out_tuple = krk_newTuple(2); /* contour, width */
|
|
krk_push(OBJECT_VAL(out_tuple));
|
|
|
|
/* if @c into is unset, make a new one to store result; otherwise, @c into is updated */
|
|
if (!contour) {
|
|
contour = (struct _yutani_TTContour*)krk_newInstance(TTContour);
|
|
}
|
|
|
|
contour->contour = tt_prepare_string_into(contour->contour, self->fontData, x, y, s, &out_width);
|
|
out_tuple->values.values[out_tuple->values.count++] = OBJECT_VAL(contour);
|
|
out_tuple->values.values[out_tuple->values.count++] = FLOATING_VAL(out_width);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
KRK_Method(Font,ellipsify) {
|
|
const char * s;
|
|
int max_width;
|
|
|
|
if (!krk_parseArgs(".si", (const char*[]){"s","w"},
|
|
&s, &max_width)) return NONE_VAL();
|
|
|
|
int out_width = 0;
|
|
char * out = tt_ellipsify(s, self->fontSize, self->fontData, max_width, &out_width);
|
|
|
|
KrkTuple * out_tuple = krk_newTuple(2);
|
|
krk_push(OBJECT_VAL(out_tuple));
|
|
|
|
out_tuple->values.values[out_tuple->values.count++] = OBJECT_VAL(krk_copyString(out, strlen(out)));
|
|
out_tuple->values.values[out_tuple->values.count++] = INTEGER_VAL(out_width);
|
|
|
|
free(out);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
WRAP_TYPE(MenuBar,struct menu_bar,menuBar);
|
|
WRAP_TYPE(MenuList,struct MenuList, menuList);
|
|
WRAP_TYPE(MenuEntry,struct MenuEntry, menuEntry);
|
|
WRAP_TYPE(MenuEntrySubmenu,struct MenuEntry, menuEntry);
|
|
WRAP_TYPE(MenuEntrySeparator,struct MenuEntry, menuEntry);
|
|
WRAP_TYPE(MenuEntryCustom,struct MenuEntry, menuEntry);
|
|
|
|
#define IS_MenuBar(o) (krk_isInstanceOf(o,MenuBar))
|
|
#define AS_MenuBar(o) ((struct _yutani_MenuBar*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_MenuBar*
|
|
|
|
static void _yutani_MenuBar_gcsweep(KrkInstance * _self) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self;
|
|
if (self->menuBar->entries) {
|
|
for (size_t i = 0; self->menuBar->entries[i].title; ++i) {
|
|
free(self->menuBar->entries[i].title);
|
|
free(self->menuBar->entries[i].action);
|
|
}
|
|
free(self->menuBar->entries);
|
|
}
|
|
free(self->menuBar);
|
|
}
|
|
|
|
static void _menubar_callback(struct menu_bar * _self) {
|
|
CURRENT_CTYPE self = _self->_private;
|
|
KrkValue callback;
|
|
if (krk_tableGet(&self->inst.fields, OBJECT_VAL(S("callback")), &callback)) {
|
|
krk_push(callback);
|
|
krk_push(OBJECT_VAL(self));
|
|
krk_callStack(1);
|
|
}
|
|
}
|
|
|
|
KRK_Method(MenuBar,__init__) {
|
|
KrkTuple * entries;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!:MenuBar", (const char*[]){"entries"},
|
|
KRK_BASE_CLASS(tuple), &entries)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
NO_REINIT(MenuBar);
|
|
|
|
size_t count = entries->values.count;
|
|
struct menu_bar * out = calloc(sizeof(struct menu_bar), 1);
|
|
out->entries = calloc(sizeof(struct menu_bar_entries), count + 1);
|
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
KrkValue entry = entries->values.values[i];
|
|
if (!IS_TUPLE(entry) || AS_TUPLE(entry)->values.count != 2 ||
|
|
!IS_STRING(AS_TUPLE(entry)->values.values[0]) || !IS_STRING(AS_TUPLE(entry)->values.values[1])) {
|
|
krk_runtimeError(vm.exceptions->typeError, "entries member should be tuple[str,str], not %T", entry);
|
|
goto _error;
|
|
}
|
|
|
|
out->entries[i].title = strdup(AS_CSTRING(AS_TUPLE(entry)->values.values[0]));
|
|
out->entries[i].action = strdup(AS_CSTRING(AS_TUPLE(entry)->values.values[1]));
|
|
}
|
|
|
|
out->entries[count].title = NULL;
|
|
out->entries[count].action = NULL;
|
|
|
|
out->set = menu_set_create();
|
|
|
|
self->menuBar = out;
|
|
out->_private = self;
|
|
out->redraw_callback = _menubar_callback;
|
|
|
|
krk_attachNamedValue(&self->inst.fields, "entries", OBJECT_VAL(entries));
|
|
krk_attachNamedValue(&self->inst.fields, "set", krk_dict_of(0,NULL,0));
|
|
|
|
return NONE_VAL();
|
|
|
|
_error:
|
|
for (size_t i = 0; i < count; ++i) {
|
|
if (out->entries[i].title) free(out->entries[i].title);
|
|
if (out->entries[i].action) free(out->entries[i].action);
|
|
}
|
|
free(out->entries);
|
|
free(out);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(MenuBar,place) {
|
|
int x, y;
|
|
unsigned int width;
|
|
struct _yutani_Window * window;
|
|
|
|
if (!krk_parseArgs(
|
|
".iiIO!", (const char*[]){"x","y","width","window"},
|
|
&x, &y, &width,
|
|
Window, &window)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(MenuBar);
|
|
|
|
self->menuBar->x = x;
|
|
self->menuBar->y = y;
|
|
self->menuBar->width = width;
|
|
self->menuBar->window = window->window;
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(MenuBar,render) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
if (!krk_parseArgs(".O!",(const char*[]){"ctx"}, GraphicsContext, &ctx)) return NONE_VAL();
|
|
INIT_CHECK(MenuBar);
|
|
menu_bar_render(self->menuBar, ctx->ctx);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(MenuBar,mouse_event) {
|
|
struct _yutani_Window * window;
|
|
KrkValue message;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!V!", (const char*[]){"window", "message"},
|
|
Window, &window,
|
|
Message_WindowMouseEvent, &message
|
|
)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(MenuBar);
|
|
return INTEGER_VAL(menu_bar_mouse_event(yctxInstance->yctx, window->window, self->menuBar,
|
|
AS_Message_WindowMouseEvent(message),
|
|
AS_Message_WindowMouseEvent(message)->new_x ,
|
|
AS_Message_WindowMouseEvent(message)->new_y));
|
|
}
|
|
|
|
KRK_Method(MenuBar,insert) {
|
|
KrkValue name;
|
|
struct _yutani_MenuList * menu;
|
|
|
|
if (!krk_parseArgs(
|
|
".V!O!", (const char*[]){"name","menu"},
|
|
KRK_BASE_CLASS(str), &name,
|
|
MenuList, &menu
|
|
)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(MenuBar);
|
|
menu_set_insert(self->menuBar->set, AS_CSTRING(name), menu->menuList);
|
|
|
|
KrkValue dict = NONE_VAL();
|
|
if (!krk_tableGet(&self->inst.fields, OBJECT_VAL(S("set")), &dict) || !krk_isInstanceOf(dict,KRK_BASE_CLASS(dict))) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "corrupt MenuBar");
|
|
}
|
|
|
|
krk_tableSet(AS_DICT(dict), name, OBJECT_VAL(menu));
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(MenuBar,height) {
|
|
return INTEGER_VAL(MENU_BAR_HEIGHT);
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define IS_MenuList(o) (krk_isInstanceOf(o,MenuList))
|
|
#define AS_MenuList(o) ((struct _yutani_MenuList*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_MenuList*
|
|
|
|
KRK_Method(MenuList,__init__) {
|
|
if (!krk_parseArgs(".:MenuList",(const char*[]){}, NULL)) return NONE_VAL();
|
|
|
|
NO_REINIT(MenuList);
|
|
|
|
struct MenuList * out = menu_create();
|
|
self->menuList = out;
|
|
|
|
KrkValue list = krk_list_of(0,NULL,0);
|
|
krk_attachNamedValue(&self->inst.fields, "entries", list);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(MenuList,insert) {
|
|
struct _yutani_MenuEntry * entry;
|
|
|
|
if (!krk_parseArgs(".O!",(const char*[]){"entry"}, MenuEntry, &entry)) return NONE_VAL();
|
|
|
|
INIT_CHECK(MenuList);
|
|
|
|
menu_insert(self->menuList, entry->menuEntry);
|
|
|
|
KrkValue list = NONE_VAL();
|
|
|
|
if (!krk_tableGet(&self->inst.fields, OBJECT_VAL(S("entries")), &list) || !IS_list(list)) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "corrupt MenuList");
|
|
}
|
|
|
|
krk_writeValueArray(AS_LIST(list), OBJECT_VAL(entry));
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define IS_MenuEntry(o) (krk_isInstanceOf(o,MenuEntry))
|
|
#define AS_MenuEntry(o) ((struct _yutani_MenuEntry*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_MenuEntry*
|
|
|
|
static void _MenuEntry_callback_internal(struct MenuEntry * _self) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self->_private;
|
|
|
|
KrkValue callback = NONE_VAL();
|
|
if (krk_tableGet(&self->inst.fields, OBJECT_VAL(S("callback")), &callback)) {
|
|
krk_push(callback);
|
|
krk_push(OBJECT_VAL(self));
|
|
krk_callStack(1);
|
|
}
|
|
}
|
|
|
|
KRK_Method(MenuEntry,__init__) {
|
|
const char * title;
|
|
KrkValue callback;
|
|
const char * icon = NULL;
|
|
const char * action = NULL;
|
|
|
|
if (!krk_parseArgs(
|
|
".sV|zz:MenuEntry", (const char*[]){"title","callback","icon","action"},
|
|
&title, &callback,
|
|
&icon, &action
|
|
)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
NO_REINIT(MenuEntry);
|
|
|
|
struct MenuEntry * out = menu_create_normal(icon, action, title, _MenuEntry_callback_internal);
|
|
self->menuEntry = out;
|
|
out->_private = self;
|
|
|
|
krk_attachNamedValue(&self->inst.fields, "callback", callback);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#define MENU_ENTRY_INT_PROP(name) \
|
|
KRK_Method(MenuEntry,name) { \
|
|
int set = 0, to = 0; \
|
|
if (!krk_parseArgs(".|i?",(const char*[]){"value"},&set,&to)) return NONE_VAL(); \
|
|
if (set) self->menuEntry-> name = to; \
|
|
return INTEGER_VAL(self->menuEntry-> name); \
|
|
}
|
|
|
|
MENU_ENTRY_INT_PROP(height)
|
|
MENU_ENTRY_INT_PROP(width)
|
|
MENU_ENTRY_INT_PROP(rwidth)
|
|
MENU_ENTRY_INT_PROP(hilight)
|
|
MENU_ENTRY_INT_PROP(offset)
|
|
|
|
|
|
KRK_Method(MenuEntry,update_icon) {
|
|
char * icon;
|
|
if (!krk_parseArgs(".z", (const char*[]){"icon"}, &icon)) return NONE_VAL();
|
|
|
|
INIT_CHECK(MenuEntry);
|
|
|
|
menu_update_icon(self->menuEntry, icon);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define IS_MenuEntrySubmenu(o) (krk_isInstanceOf(o,MenuEntrySubmenu))
|
|
#define AS_MenuEntrySubmenu(o) ((struct _yutani_MenuEntrySubmenu*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_MenuEntrySubmenu*
|
|
|
|
KRK_Method(MenuEntrySubmenu,__init__) {
|
|
const char * title;
|
|
const char * action = NULL;
|
|
const char * icon = NULL;
|
|
|
|
if (!krk_parseArgs(
|
|
".ss|z:MenuEntrySubmenu", (const char*[]){"title","action","icon"},
|
|
&title,
|
|
&action,
|
|
&icon
|
|
)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
NO_REINIT(MenuEntrySubmenu);
|
|
|
|
struct MenuEntry * out = menu_create_submenu(icon, action, title);
|
|
self->menuEntry = out;
|
|
out->_private = self;
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define IS_MenuEntrySeparator(o) (krk_isInstanceOf(o,MenuEntrySeparator))
|
|
#define AS_MenuEntrySeparator(o) ((struct _yutani_MenuEntrySeparator*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_MenuEntrySeparator*
|
|
|
|
KRK_Method(MenuEntrySeparator,__init__) {
|
|
if (!krk_parseArgs(".:MenuEntrySeparator", (const char*[]){}, NULL)) return NONE_VAL();
|
|
NO_REINIT(MenuEntrySeparator);
|
|
struct MenuEntry * out = menu_create_separator();
|
|
self->menuEntry = out;
|
|
out->_private = self;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define IS_MenuEntryCustom(o) (krk_isInstanceOf(o,MenuEntryCustom))
|
|
#define AS_MenuEntryCustom(o) ((struct _yutani_MenuEntryCustom*)AS_OBJECT(o))
|
|
#define CURRENT_CTYPE struct _yutani_MenuEntryCustom*
|
|
|
|
static void _custom_menu_render(gfx_context_t * ctx, struct MenuEntry * _self, int offset) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self->_private;
|
|
KrkClass * myClass = self->inst._class;
|
|
KrkValue method;
|
|
if (!krk_tableGet_fast(&myClass->methods, S("render"), &method)) return;
|
|
krk_push(method);
|
|
krk_push(OBJECT_VAL(self));
|
|
|
|
struct _yutani_GraphicsContext * gctx = (struct _yutani_GraphicsContext*)krk_newInstance(GraphicsContext);
|
|
gctx->ctx = ctx;
|
|
krk_push(OBJECT_VAL(gctx));
|
|
krk_push(INTEGER_VAL(offset));
|
|
|
|
krk_callStack(3);
|
|
}
|
|
|
|
static void _custom_menu_focus_change(struct MenuEntry * _self, int focused) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self->_private;
|
|
KrkClass * myClass = self->inst._class;
|
|
KrkValue method;
|
|
if (!krk_tableGet_fast(&myClass->methods, S("focus_change"), &method)) return;
|
|
krk_push(method);
|
|
krk_push(OBJECT_VAL(self));
|
|
krk_push(BOOLEAN_VAL(focused));
|
|
krk_callStack(2);
|
|
}
|
|
|
|
static void _custom_menu_activate(struct MenuEntry * _self, int focused) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self->_private;
|
|
KrkClass * myClass = self->inst._class;
|
|
KrkValue method;
|
|
if (!krk_tableGet_fast(&myClass->methods, S("activate"), &method)) return;
|
|
krk_push(method);
|
|
krk_push(OBJECT_VAL(self));
|
|
krk_push(BOOLEAN_VAL(focused));
|
|
krk_callStack(2);
|
|
}
|
|
|
|
static int _custom_menu_mouse_event(struct MenuEntry * _self, struct yutani_msg_window_mouse_event * event) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self->_private;
|
|
KrkClass * myClass = self->inst._class;
|
|
KrkValue method;
|
|
if (!krk_tableGet_fast(&myClass->methods, S("mouse_event"), &method)) return 0;
|
|
krk_push(method);
|
|
krk_push(OBJECT_VAL(self));
|
|
|
|
size_t size = sizeof(yutani_msg_t) + sizeof(struct yutani_msg_window_mouse_event);
|
|
yutani_msg_t * tmp = malloc(size);
|
|
tmp->type = YUTANI_MSG_WINDOW_MOUSE_EVENT;
|
|
tmp->size = size;
|
|
memcpy(tmp->data, event, sizeof(struct yutani_msg_window_mouse_event));
|
|
|
|
krk_push(makeMessage(tmp));
|
|
|
|
KrkValue result = krk_callStack(2);
|
|
if (IS_INTEGER(result)) return AS_INTEGER(result);
|
|
return 0;
|
|
}
|
|
|
|
static struct MenuEntryVTable _custom_menu_vtable = {
|
|
.methods = 4,
|
|
.renderer = _custom_menu_render,
|
|
.focus_change = _custom_menu_focus_change,
|
|
.activate = _custom_menu_activate,
|
|
.mouse_event = _custom_menu_mouse_event,
|
|
};
|
|
|
|
KRK_Method(MenuEntryCustom,__init__) {
|
|
if (!krk_parseArgs(".:MenuEntryCustom", (const char*[]){}, NULL)) return NONE_VAL();
|
|
NO_REINIT(MenuEntryCustom);
|
|
struct MenuEntry * out = menu_create_separator(); /* Steal some defaults */
|
|
out->_type = -1; /* Special */
|
|
out->vtable = &_custom_menu_vtable;
|
|
self->menuEntry = out;
|
|
out->_private = self;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
#define CURRENT_CTYPE struct _yutani_TTContour*
|
|
|
|
void _TTContour_ongcsweep(KrkInstance * _self) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self;
|
|
if (self->contour) {
|
|
free(self->contour);
|
|
}
|
|
self->contour = NULL;
|
|
}
|
|
|
|
KRK_Method(TTContour,__init__) {
|
|
float x, y;
|
|
if (!krk_parseArgs(".ff:TTContour", (const char*[]){"x","y"}, &x, &y))
|
|
return NONE_VAL();
|
|
|
|
NO_REINIT(TTContour);
|
|
self->contour = tt_contour_start(x,y);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TTContour,line_to) {
|
|
float x, y;
|
|
if (!krk_parseArgs(".ff", (const char*[]){"x","y"}, &x, &y))
|
|
return NONE_VAL();
|
|
INIT_CHECK(TTContour);
|
|
self->contour = tt_contour_line_to(self->contour, x, y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TTContour,move_to) {
|
|
float x, y;
|
|
if (!krk_parseArgs(".ff", (const char*[]){"x","y"}, &x, &y))
|
|
return NONE_VAL();
|
|
INIT_CHECK(TTContour);
|
|
self->contour = tt_contour_move_to(self->contour, x, y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TTContour,finish) {
|
|
INIT_CHECK(TTContour);
|
|
struct _yutani_TTShape * newShape = (struct _yutani_TTShape*)krk_newInstance(TTShape);
|
|
newShape->shape = tt_contour_finish(self->contour);
|
|
return OBJECT_VAL(newShape);
|
|
}
|
|
|
|
KRK_Method(TTContour,stroke) {
|
|
float width;
|
|
if (!krk_parseArgs(".f", (const char*[]){"width"}, &width)) return NONE_VAL();
|
|
INIT_CHECK(TTContour);
|
|
struct _yutani_TTShape * newShape = (struct _yutani_TTShape*)krk_newInstance(TTShape);
|
|
newShape->shape = tt_contour_stroke_shape(self->contour, width);
|
|
return OBJECT_VAL(newShape);
|
|
}
|
|
|
|
KRK_Method(TTContour,stroke_path) {
|
|
float width;
|
|
if (!krk_parseArgs(".f", (const char*[]){"width"}, &width)) return NONE_VAL();
|
|
INIT_CHECK(TTContour);
|
|
struct _yutani_TTContour * newContour = (struct _yutani_TTContour*)krk_newInstance(TTContour);
|
|
newContour->contour = tt_contour_stroke_contour(self->contour, width);
|
|
return OBJECT_VAL(newContour);
|
|
}
|
|
|
|
KRK_Method(TTContour,free) {
|
|
INIT_CHECK(TTContour);
|
|
free(self->contour);
|
|
self->contour = NULL;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TTContour,transform) {
|
|
struct _yutani_TransformMatrix * matrix;
|
|
if (!krk_parseArgs(".O!", (const char*[]){"matrix"},
|
|
TransformMatrix, &matrix)) return NONE_VAL();
|
|
INIT_CHECK(TTContour);
|
|
|
|
tt_contour_transform(self->contour, matrix->matrix);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
#define CURRENT_CTYPE struct _yutani_TTShape*
|
|
|
|
void _TTShape_ongcsweep(KrkInstance * _self) {
|
|
CURRENT_CTYPE self = (CURRENT_CTYPE)_self;
|
|
if (self->shape) {
|
|
fprintf(stderr, "free shape\n");
|
|
free(self->shape);
|
|
}
|
|
self->shape = NULL;
|
|
}
|
|
|
|
KRK_Method(TTShape,__init__) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "Can not initialize empty shape; use TTContour.finish instead");
|
|
}
|
|
|
|
KRK_Method(TTShape,paint) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
uint32_t color;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!I", (const char*[]){"ctx","color"},
|
|
GraphicsContext, &ctx, &color)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(TTShape);
|
|
|
|
tt_path_paint(ctx->ctx, self->shape, color);
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
extern void tt_path_paint_sprite(gfx_context_t * ctx, const struct TT_Shape * shape, sprite_t * sprite, gfx_matrix_t matrix);
|
|
extern void tt_path_paint_sprite_options(gfx_context_t * ctx, const struct TT_Shape * shape, sprite_t * sprite, gfx_matrix_t matrix, int, int);
|
|
KRK_Method(TTShape,paint_sprite) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
struct _yutani_Sprite * sprite;
|
|
struct _yutani_TransformMatrix * matrix;
|
|
|
|
int filter = 0;
|
|
int wrap = 0;
|
|
|
|
if (!krk_parseArgs(
|
|
".O!O!O!|ii", (const char*[]){"ctx","sprite","matrix","filter","wrap"},
|
|
GraphicsContext, &ctx,
|
|
Sprite, &sprite,
|
|
TransformMatrix, &matrix,
|
|
&filter, &wrap)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
INIT_CHECK(TTShape);
|
|
if (!sprite->sprite) return krk_runtimeError(vm.exceptions->valueError, "sprite go brrr");
|
|
|
|
if (filter == 0 && wrap == 0) {
|
|
tt_path_paint_sprite(ctx->ctx, self->shape, sprite->sprite, matrix->matrix);
|
|
} else {
|
|
tt_path_paint_sprite_options(ctx->ctx, self->shape, sprite->sprite, matrix->matrix, filter, wrap);
|
|
}
|
|
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Method(TTShape,free) {
|
|
INIT_CHECK(TTShape);
|
|
free(self->shape);
|
|
self->shape = NULL;
|
|
return NONE_VAL();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
KRK_Function(decor_get_bounds) {
|
|
struct _yutani_Window * window = NULL;
|
|
if (!krk_parseArgs("|O!",(const char *[]){"window"}, Window, &window)) return NONE_VAL();
|
|
if (window && !window->window) return krk_runtimeError(vm.exceptions->valueError, "Window is closed");
|
|
struct decor_bounds bounds;
|
|
decor_get_bounds(window ? window->window : NULL, &bounds);
|
|
|
|
KrkValue result = krk_dict_of(0, NULL, 0);
|
|
krk_push(result);
|
|
#define SET(val) krk_attachNamedValue(AS_DICT(result), #val, INTEGER_VAL(bounds. val));
|
|
|
|
SET(top_height);
|
|
SET(bottom_height);
|
|
SET(left_width);
|
|
SET(right_width);
|
|
SET(width);
|
|
SET(height);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
KRK_Function(decor_render) {
|
|
struct _yutani_Window * window;
|
|
const char * title = NULL;
|
|
if (!krk_parseArgs("O!|z",(const char *[]){"window","title"}, Window, &window, &title)) return NONE_VAL();
|
|
if (!window->window) return krk_runtimeError(vm.exceptions->valueError, "Window is closed");
|
|
if (!title) title = IS_NONE(window->title) ? "" : AS_CSTRING(window->title);
|
|
render_decorations(window->window, window->ctx, (char*)title);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Function(decor_handle_event) {
|
|
struct _yutani_Message * message = NULL;
|
|
if (!krk_parseArgs("O!",(const char *[]){"message"}, Message, &message)) return NONE_VAL();
|
|
return INTEGER_VAL(decor_handle_event(yctxInstance->yctx, message->msg));
|
|
}
|
|
|
|
KRK_Function(decor_show_default_menu) {
|
|
struct _yutani_Window * window;
|
|
int x, y;
|
|
if (!krk_parseArgs("O!ii",(const char *[]){"window","x","y"}, Window, &window, &x, &y)) return NONE_VAL();
|
|
if (!window->window) return krk_runtimeError(vm.exceptions->valueError, "Window is closed");
|
|
decor_show_default_menu(window->window, x, y);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Function(rgb) {
|
|
int r, g, b;
|
|
KrkValue a = NONE_VAL();
|
|
if (!krk_parseArgs("bbb|V",(const char*[]){"r","g","b","a"}, &r, &g, &b, &a)) return NONE_VAL();
|
|
if (IS_NONE(a)) {
|
|
return INTEGER_VAL(rgb(r,g,b));
|
|
} else {
|
|
if (IS_FLOATING(a)) a = INTEGER_VAL(AS_FLOATING(a) * 255);
|
|
if (!IS_INTEGER(a)) return TYPE_ERROR(int or float,a);
|
|
return INTEGER_VAL(rgba(r,g,b,AS_INTEGER(a)));
|
|
}
|
|
}
|
|
|
|
KRK_Function(draw_button) {
|
|
struct _yutani_GraphicsContext * ctx;
|
|
int x, y, width, height, hilight;
|
|
const char * title;
|
|
|
|
if (!krk_parseArgs("O!iiIIsi",
|
|
(const char*[]){"ctx","x","y","width","height","title","hilight"},
|
|
GraphicsContext, &ctx,
|
|
&x, &y, &width, &height,
|
|
&title, &hilight)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
struct TTKButton button = {x,y,width,height,(char*)title,hilight};
|
|
ttk_button_draw(ctx->ctx, &button);
|
|
return NONE_VAL();
|
|
}
|
|
|
|
KRK_Function(fswait) {
|
|
KrkTuple * fds;
|
|
int timeout = -1;
|
|
|
|
if (!krk_parseArgs("O!|i",(const char*[]){"fds","timeout"},
|
|
KRK_BASE_CLASS(tuple), &fds,
|
|
&timeout)) {
|
|
return NONE_VAL();
|
|
}
|
|
|
|
size_t count = fds->values.count;
|
|
|
|
if (!count) {
|
|
return krk_runtimeError(vm.exceptions->typeError, "can not wait on nothing?");
|
|
}
|
|
|
|
/* Spot check first */
|
|
for (size_t i = 0; i < count; ++i) {
|
|
KrkValue val = fds->values.values[i];
|
|
if (!IS_INTEGER(val)) return krk_runtimeError(vm.exceptions->typeError, "fds must be tuple of int, not %T", val);
|
|
}
|
|
|
|
int * _fds = malloc(sizeof(int) * count);
|
|
int * _results = malloc(sizeof(int) * count);
|
|
for (size_t i = 0; i < count; ++i) {
|
|
KrkValue val = fds->values.values[i];
|
|
_fds[i] = AS_INTEGER(val);
|
|
_results[i] = 0;
|
|
}
|
|
|
|
errno = 0;
|
|
int status = fswait3(count, _fds, timeout, _results);
|
|
free(_fds);
|
|
|
|
if (status < 0) {
|
|
int _errno = errno;
|
|
free(_results);
|
|
/* check if we were already raising a keyboard interrupt */
|
|
if (krk_currentThread.flags & (KRK_THREAD_HAS_EXCEPTION | KRK_THREAD_SIGNALLED)) return NONE_VAL();
|
|
return krk_runtimeError(vm.exceptions->OSError, "%s", strerror(_errno));
|
|
}
|
|
|
|
KrkTuple * output = krk_newTuple(count);
|
|
krk_push(OBJECT_VAL(output));
|
|
for (size_t i = 0; i < count; ++i) {
|
|
output->values.values[output->values.count++] = INTEGER_VAL(_results[i]);
|
|
}
|
|
|
|
free(_results);
|
|
|
|
return krk_pop();
|
|
}
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
|
KRK_Module(_yutani2) {
|
|
_module = module;
|
|
/**
|
|
* Base message type
|
|
*/
|
|
krk_makeClass(module, &Message, "Message", KRK_BASE_CLASS(object));
|
|
Message->allocSize = sizeof(struct _yutani_Message);
|
|
Message->_ongcsweep = _Message_gcsweep;
|
|
BIND_STATICMETHOD(Message,__new__);
|
|
BIND_METHOD(Message,__repr__);
|
|
BIND_PROP(Message,msg_magic);
|
|
BIND_PROP(Message,msg_type);
|
|
BIND_PROP(Message,msg_size);
|
|
#define TYPE(type) krk_attachNamedValue(&Message->methods, "MSG_" #type, INTEGER_VAL(YUTANI_MSG_ ## type))
|
|
TYPE(HELLO); TYPE(WINDOW_NEW); TYPE(FLIP); TYPE(KEY_EVENT); TYPE(MOUSE_EVENT);
|
|
TYPE(WINDOW_MOVE); TYPE(WINDOW_CLOSE); TYPE(WINDOW_SHOW); TYPE(WINDOW_HIDE);
|
|
TYPE(WINDOW_STACK); TYPE(WINDOW_FOCUS_CHANGE); TYPE(WINDOW_MOUSE_EVENT);
|
|
TYPE(FLIP_REGION); TYPE(WINDOW_NEW_FLAGS); TYPE(RESIZE_REQUEST);
|
|
TYPE(RESIZE_OFFER); TYPE(RESIZE_ACCEPT); TYPE(RESIZE_BUFID); TYPE(RESIZE_DONE);
|
|
TYPE(WINDOW_ADVERTISE); TYPE(SUBSCRIBE); TYPE(UNSUBSCRIBE); TYPE(NOTIFY);
|
|
TYPE(QUERY_WINDOWS); TYPE(WINDOW_FOCUS); TYPE(WINDOW_DRAG_START); TYPE(WINDOW_WARP_MOUSE);
|
|
TYPE(WINDOW_SHOW_MOUSE); TYPE(WINDOW_RESIZE_START); TYPE(SESSION_END);
|
|
TYPE(KEY_BIND); TYPE(WINDOW_UPDATE_SHAPE); TYPE(CLIPBOARD); TYPE(GOODBYE);
|
|
TYPE(SPECIAL_REQUEST); TYPE(WELCOME); TYPE(WINDOW_INIT);
|
|
#undef TYPE
|
|
krk_finalizeClass(Message);
|
|
|
|
#define MAKE_MSG(type) \
|
|
krk_makeClass(module, &Message_ ## type, "Message_" # type, Message)
|
|
|
|
MAKE_MSG(Welcome);
|
|
BIND_PROP(Message_Welcome,display_width);
|
|
BIND_PROP(Message_Welcome,display_height);
|
|
krk_finalizeClass(Message_Welcome);
|
|
|
|
MAKE_MSG(WindowMouseEvent);
|
|
BIND_PROP(Message_WindowMouseEvent,wid);
|
|
BIND_PROP(Message_WindowMouseEvent,new_x);
|
|
BIND_PROP(Message_WindowMouseEvent,new_y);
|
|
BIND_PROP(Message_WindowMouseEvent,old_x);
|
|
BIND_PROP(Message_WindowMouseEvent,old_y);
|
|
BIND_PROP(Message_WindowMouseEvent,buttons);
|
|
BIND_PROP(Message_WindowMouseEvent,command);
|
|
BIND_PROP(Message_WindowMouseEvent,modifiers);
|
|
krk_finalizeClass(Message_WindowMouseEvent);
|
|
|
|
MAKE_MSG(WindowFocusChange);
|
|
BIND_PROP(Message_WindowFocusChange,wid);
|
|
BIND_PROP(Message_WindowFocusChange,focused);
|
|
krk_finalizeClass(Message_WindowFocusChange);
|
|
|
|
MAKE_MSG(ResizeOffer);
|
|
BIND_PROP(Message_ResizeOffer,wid);
|
|
BIND_PROP(Message_ResizeOffer,width);
|
|
BIND_PROP(Message_ResizeOffer,height);
|
|
BIND_PROP(Message_ResizeOffer,bufid);
|
|
krk_finalizeClass(Message_ResizeOffer);
|
|
|
|
MAKE_MSG(WindowAdvertise);
|
|
BIND_PROP(Message_WindowAdvertise,wid);
|
|
BIND_PROP(Message_WindowAdvertise,flags);
|
|
BIND_PROP(Message_WindowAdvertise,size);
|
|
BIND_PROP(Message_WindowAdvertise,width);
|
|
BIND_PROP(Message_WindowAdvertise,height);
|
|
BIND_PROP(Message_WindowAdvertise,bufid);
|
|
BIND_PROP(Message_WindowAdvertise,name);
|
|
BIND_PROP(Message_WindowAdvertise,icon);
|
|
krk_finalizeClass(Message_WindowAdvertise);
|
|
|
|
MAKE_MSG(WindowMove);
|
|
BIND_PROP(Message_WindowMove,wid);
|
|
BIND_PROP(Message_WindowMove,x);
|
|
BIND_PROP(Message_WindowMove,y);
|
|
krk_finalizeClass(Message_WindowMove);
|
|
|
|
MAKE_MSG(KeyEvent);
|
|
BIND_PROP(Message_KeyEvent,wid);
|
|
BIND_PROP(Message_KeyEvent,keycode);
|
|
BIND_PROP(Message_KeyEvent,modifiers);
|
|
BIND_PROP(Message_KeyEvent,action);
|
|
BIND_PROP(Message_KeyEvent,key);
|
|
BIND_PROP(Message_KeyEvent,kbd_state);
|
|
BIND_PROP(Message_KeyEvent,kbd_s_state);
|
|
BIND_PROP(Message_KeyEvent,k_ctrl);
|
|
BIND_PROP(Message_KeyEvent,k_shift);
|
|
BIND_PROP(Message_KeyEvent,k_alt);
|
|
BIND_PROP(Message_KeyEvent,k_super);
|
|
BIND_PROP(Message_KeyEvent,kl_ctrl);
|
|
BIND_PROP(Message_KeyEvent,kl_shift);
|
|
BIND_PROP(Message_KeyEvent,kl_alt);
|
|
BIND_PROP(Message_KeyEvent,kl_super);
|
|
BIND_PROP(Message_KeyEvent,kr_ctrl);
|
|
BIND_PROP(Message_KeyEvent,kr_shift);
|
|
BIND_PROP(Message_KeyEvent,kr_alt);
|
|
BIND_PROP(Message_KeyEvent,kr_super);
|
|
BIND_PROP(Message_KeyEvent,kbd_esc_buf);
|
|
krk_finalizeClass(Message_KeyEvent);
|
|
|
|
MAKE_MSG(WindowClose);
|
|
BIND_PROP(Message_WindowClose,wid);
|
|
krk_finalizeClass(Message_WindowClose);
|
|
|
|
/**
|
|
* Core connection type; singleton
|
|
*
|
|
* class YutaniCtx:
|
|
* display_width: int
|
|
* display_height: int
|
|
* def __new__(cls)
|
|
* def poll(self, sync=True) -> Message
|
|
* def wait_for(self, msgtype: int) -> Message
|
|
* def subscribe(self)
|
|
* def unsubscribe(self)
|
|
* def query_windows(self)
|
|
* def fileno(self) -> int
|
|
* def query(self) -> int
|
|
* def menu_process_event(self, message: Message) -> int
|
|
*/
|
|
krk_makeClass(module, &YutaniCtx, "YutaniCtx", KRK_BASE_CLASS(object));
|
|
YutaniCtx->allocSize = sizeof(struct _yutani_YutaniCtx);
|
|
YutaniCtx->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
|
BIND_STATICMETHOD(YutaniCtx,__new__);
|
|
BIND_METHOD(YutaniCtx,poll);
|
|
BIND_METHOD(YutaniCtx,wait_for);
|
|
BIND_METHOD(YutaniCtx,subscribe);
|
|
BIND_METHOD(YutaniCtx,unsubscribe);
|
|
BIND_METHOD(YutaniCtx,query_windows);
|
|
BIND_METHOD(YutaniCtx,fileno);
|
|
BIND_METHOD(YutaniCtx,query);
|
|
BIND_METHOD(YutaniCtx,menu_process_event);
|
|
BIND_PROP(YutaniCtx,display_width);
|
|
BIND_PROP(YutaniCtx,display_height);
|
|
krk_finalizeClass(YutaniCtx);
|
|
|
|
/*
|
|
* Generic graphics context.
|
|
* Subclassed by Window and Sprite.
|
|
*
|
|
* class GraphicsContext:
|
|
* width: int
|
|
* height: int
|
|
* isDoubleBuffered: bool
|
|
* def fill(self, color: int)
|
|
* def flip(self)
|
|
* def blur(self, radius: int = 2)
|
|
* def line(self, x0: int, x1: int, y0: int, y1: int, color: int, thickness=None)
|
|
* def rect(self, x: int, y: int, width: int, height: int, color: int, solid: bool = False, radius: int = 0)
|
|
* def draw_sprite(self, sprite: Sprite, x: int, y: int, alpha: float = 1.0, rotation: float = 0.0, scale: tuple[int,int] = None, color: int = 0)
|
|
*
|
|
* To allocate a new graphics context with a fresh backing store, use Sprite.
|
|
*/
|
|
krk_makeClass(module, &GraphicsContext, "GraphicsContext", KRK_BASE_CLASS(object));
|
|
GraphicsContext->allocSize = sizeof(struct _yutani_GraphicsContext);
|
|
GraphicsContext->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
|
BIND_STATICMETHOD(GraphicsContext,__new__);
|
|
BIND_PROP(GraphicsContext,width);
|
|
BIND_PROP(GraphicsContext,height);
|
|
BIND_PROP(GraphicsContext,isDoubleBuffered);
|
|
BIND_METHOD(GraphicsContext,fill);
|
|
BIND_METHOD(GraphicsContext,flip);
|
|
BIND_METHOD(GraphicsContext,blur);
|
|
BIND_METHOD(GraphicsContext,line);
|
|
BIND_METHOD(GraphicsContext,rect);
|
|
BIND_METHOD(GraphicsContext,draw_sprite);
|
|
krk_finalizeClass(GraphicsContext);
|
|
|
|
/*
|
|
* Graphics object with a bitmap backing store,
|
|
* typically derived from an image file.
|
|
*
|
|
* class Sprite(GraphicsContext):
|
|
* def __init__(self, file=None, width=0, height=0)
|
|
*/
|
|
krk_makeClass(module, &Sprite, "Sprite", GraphicsContext);
|
|
Sprite->allocSize = sizeof(struct _yutani_Sprite);
|
|
Sprite->_ongcsweep = _yutani_Sprite_gcsweep;
|
|
BIND_METHOD(Sprite,__init__);
|
|
BIND_METHOD(Sprite,__repr__);
|
|
BIND_METHOD(Sprite,free);
|
|
krk_finalizeClass(Sprite);
|
|
|
|
/*
|
|
* A window.
|
|
*
|
|
* class Window(GraphicsContext):
|
|
* title: str
|
|
* icon: str
|
|
* wid: int
|
|
* x: int
|
|
* y: int
|
|
* focused: bool
|
|
* closed: bool
|
|
* def __init__(self, width: int, height: int, flags: int = 0, title: str = None, icon: str = None, doublebuffer: bool = True)
|
|
* def flip(self)
|
|
* def move(self, x: int, y: int)
|
|
* def close(self)
|
|
* def set_stack(self, z: int)
|
|
* def special_request(self: request: int)
|
|
* def resize(self, width: int, height: int)
|
|
* def resize_start(self, direction: int)
|
|
* def resize_done(self)
|
|
* def resize_offer(self, width: int, height: int)
|
|
* def resize_accept(self, width: int, height: int)
|
|
* def update_shape(self, threshold: int)
|
|
* def show_mouse(self, mouse: int)
|
|
* def warp_mouse(self, x: int, y: int)
|
|
* def reinit(self)
|
|
*/
|
|
krk_makeClass(module, &Window, "Window", GraphicsContext);
|
|
Window->allocSize = sizeof(struct _yutani_Window);
|
|
Window->_ongcscan = _yutani_Window_gcscan;
|
|
BIND_METHOD(Window,__init__);
|
|
BIND_METHOD(Window,__repr__);
|
|
BIND_METHOD(Window,flip);
|
|
BIND_METHOD(Window,move);
|
|
BIND_METHOD(Window,close);
|
|
BIND_METHOD(Window,set_stack);
|
|
BIND_METHOD(Window,special_request);
|
|
BIND_METHOD(Window,resize);
|
|
BIND_METHOD(Window,resize_start);
|
|
BIND_METHOD(Window,resize_done);
|
|
BIND_METHOD(Window,resize_offer);
|
|
BIND_METHOD(Window,resize_accept);
|
|
BIND_METHOD(Window,update_shape);
|
|
BIND_METHOD(Window,show_mouse);
|
|
BIND_METHOD(Window,warp_mouse);
|
|
BIND_METHOD(Window,reinit);
|
|
|
|
BIND_PROP(Window,title);
|
|
BIND_PROP(Window,icon);
|
|
BIND_PROP(Window,wid);
|
|
BIND_PROP(Window,x);
|
|
BIND_PROP(Window,y);
|
|
BIND_PROP(Window,focused);
|
|
BIND_PROP(Window,closed);
|
|
krk_finalizeClass(Window);
|
|
|
|
krk_makeClass(module, &Subregion, "Subregion", GraphicsContext);
|
|
Subregion->allocSize = sizeof(struct _yutani_Subregion);
|
|
Subregion->_ongcsweep = _yutani_Subregion_gcsweep;
|
|
BIND_METHOD(Subregion,__init__);
|
|
BIND_PROP(Subregion,offset_x);
|
|
BIND_PROP(Subregion,offset_y);
|
|
krk_finalizeClass(Subregion);
|
|
|
|
/*
|
|
* Typeface using the 'text' library.
|
|
*
|
|
* class Font:
|
|
* size: int
|
|
* def __init__(self, font: str, size: int, color: int = rgb(0,0,0))
|
|
* def draw_string(self, ctx: GraphicsContext, s: str, x: int, y: int) -> int
|
|
* def draw_string_shadow(self, ctx: GraphicsContext, s: str, x: int, y: int, shadow: int, blur: int)
|
|
* def width(self, s: str) -> int
|
|
*/
|
|
krk_makeClass(module, &Font, "Font", KRK_BASE_CLASS(object));
|
|
Font->allocSize = sizeof(struct _yutani_Font);
|
|
Font->_ongcsweep = _yutani_Font_gcsweep;
|
|
BIND_METHOD(Font,__init__);
|
|
BIND_METHOD(Font,draw_string);
|
|
BIND_METHOD(Font,draw_string_shadow);
|
|
BIND_METHOD(Font,width);
|
|
BIND_METHOD(Font,measure);
|
|
BIND_METHOD(Font,draw_glyph_into);
|
|
BIND_METHOD(Font,prepare_string);
|
|
BIND_METHOD(Font,ellipsify);
|
|
BIND_PROP(Font,size);
|
|
krk_finalizeClass(Font);
|
|
|
|
/*
|
|
* Menu bar widget.
|
|
*
|
|
* This should really be in a higher-level GUI toolkit, but for now we have what we have...
|
|
*
|
|
* class MenuBar:
|
|
* def __init__(self, entries: tuple[tuple[str,str]])
|
|
* def place(self, x: int, y: int, width: int, window: Window)
|
|
* def render(self, ctx: GraphicsContext)
|
|
* def mouse_event(self, window: Window, message: Message_WindowMouseEvent)
|
|
* def insert(self, name: str, menu: MenuList)
|
|
*/
|
|
krk_makeClass(module, &MenuBar, "MenuBar", KRK_BASE_CLASS(object));
|
|
MenuBar->allocSize = sizeof(struct _yutani_MenuBar);
|
|
MenuBar->_ongcsweep = _yutani_MenuBar_gcsweep;
|
|
BIND_METHOD(MenuBar,__init__);
|
|
BIND_METHOD(MenuBar,place);
|
|
BIND_METHOD(MenuBar,render);
|
|
BIND_METHOD(MenuBar,mouse_event);
|
|
BIND_METHOD(MenuBar,insert);
|
|
BIND_PROP(MenuBar,height);
|
|
|
|
krk_finalizeClass(MenuBar);
|
|
|
|
/*
|
|
* MenuList wrapper
|
|
*
|
|
* class MenuList:
|
|
* def __init__(self)
|
|
* def insert(self, entry: MenuEntry)
|
|
*/
|
|
krk_makeClass(module, &MenuList, "MenuList", KRK_BASE_CLASS(object));
|
|
MenuList->allocSize = sizeof(struct _yutani_MenuList);
|
|
/* XXX where is the cleanup function for this? */
|
|
BIND_METHOD(MenuList,__init__);
|
|
BIND_METHOD(MenuList,insert);
|
|
krk_finalizeClass(MenuList);
|
|
|
|
|
|
/*
|
|
* Menu entry wrapper.
|
|
*
|
|
* class MenuEntry:
|
|
* def __init__(self, title: str, callback: function, icon: str = None, action: str = None)
|
|
*/
|
|
krk_makeClass(module, &MenuEntry, "MenuEntry", KRK_BASE_CLASS(object));
|
|
MenuEntry->allocSize = sizeof(struct _yutani_MenuEntry);
|
|
BIND_METHOD(MenuEntry,__init__);
|
|
BIND_PROP(MenuEntry,height);
|
|
BIND_PROP(MenuEntry,width);
|
|
BIND_PROP(MenuEntry,rwidth);
|
|
BIND_PROP(MenuEntry,hilight);
|
|
BIND_PROP(MenuEntry,offset);
|
|
BIND_METHOD(MenuEntry,update_icon);
|
|
krk_finalizeClass(MenuEntry);
|
|
|
|
/*
|
|
* Submenu subtype
|
|
*
|
|
* class MenuEntrySubmenu(MenuEntry):
|
|
* def __init__(self, title: str, icon: str = None, action: str = None)
|
|
*/
|
|
krk_makeClass(module, &MenuEntrySubmenu, "MenuEntrySubmenu", MenuEntry);
|
|
MenuEntrySubmenu->allocSize = sizeof(struct _yutani_MenuEntrySubmenu);
|
|
BIND_METHOD(MenuEntrySubmenu,__init__);
|
|
krk_finalizeClass(MenuEntrySubmenu);
|
|
|
|
/**
|
|
* Separator subtype
|
|
*
|
|
* class MenuEntrySeparator(MenuEntry):
|
|
* def __init__(self)
|
|
*/
|
|
krk_makeClass(module, &MenuEntrySeparator, "MenuEntrySeparator", MenuEntry);
|
|
MenuEntrySeparator->allocSize = sizeof(struct _yutani_MenuEntrySeparator);
|
|
BIND_METHOD(MenuEntrySeparator,__init__);
|
|
krk_finalizeClass(MenuEntrySeparator);
|
|
|
|
krk_makeClass(module, &MenuEntryCustom, "MenuEntryCustom", MenuEntry);
|
|
MenuEntryCustom->allocSize = sizeof(struct _yutani_MenuEntryCustom);
|
|
BIND_METHOD(MenuEntryCustom,__init__);
|
|
krk_finalizeClass(MenuEntryCustom);
|
|
|
|
|
|
krk_makeClass(module, &TTContour, "TTContour", KRK_BASE_CLASS(object));
|
|
TTContour->allocSize = sizeof(struct _yutani_TTContour);
|
|
TTContour->_ongcsweep = _TTContour_ongcsweep;
|
|
BIND_METHOD(TTContour,__init__);
|
|
BIND_METHOD(TTContour,line_to);
|
|
BIND_METHOD(TTContour,move_to);
|
|
BIND_METHOD(TTContour,finish);
|
|
BIND_METHOD(TTContour,free);
|
|
BIND_METHOD(TTContour,stroke);
|
|
BIND_METHOD(TTContour,stroke_path);
|
|
BIND_METHOD(TTContour,transform);
|
|
krk_finalizeClass(TTContour);
|
|
|
|
krk_makeClass(module, &TTShape, "TTShape", KRK_BASE_CLASS(object));
|
|
TTShape->allocSize = sizeof(struct _yutani_TTShape);
|
|
TTShape->_ongcsweep = _TTShape_ongcsweep;
|
|
BIND_METHOD(TTShape,__init__);
|
|
BIND_METHOD(TTShape,paint);
|
|
BIND_METHOD(TTShape,paint_sprite);
|
|
BIND_METHOD(TTShape,free);
|
|
#define CONST(n) krk_attachNamedValue(&TTShape->methods, #n, INTEGER_VAL(n))
|
|
CONST(TT_PATH_FILTER_BILINEAR);
|
|
CONST(TT_PATH_FILTER_NEAREST);
|
|
CONST(TT_PATH_WRAP_REPEAT);
|
|
CONST(TT_PATH_WRAP_NONE);
|
|
CONST(TT_PATH_WRAP_PAD);
|
|
#undef CONST
|
|
krk_finalizeClass(TTShape);
|
|
|
|
krk_makeClass(module, &TransformMatrix, "TransformMatrix", KRK_BASE_CLASS(object));
|
|
TransformMatrix->allocSize = sizeof(struct _yutani_TransformMatrix);
|
|
BIND_METHOD(TransformMatrix,__init__);
|
|
BIND_METHOD(TransformMatrix,__repr__);
|
|
BIND_METHOD(TransformMatrix,scale);
|
|
BIND_METHOD(TransformMatrix,translate);
|
|
BIND_METHOD(TransformMatrix,rotate);
|
|
BIND_METHOD(TransformMatrix,shear);
|
|
BIND_METHOD(TransformMatrix,apply);
|
|
BIND_PROP(TransformMatrix,a);
|
|
BIND_PROP(TransformMatrix,b);
|
|
BIND_PROP(TransformMatrix,tx);
|
|
BIND_PROP(TransformMatrix,c);
|
|
BIND_PROP(TransformMatrix,d);
|
|
BIND_PROP(TransformMatrix,ty);
|
|
krk_finalizeClass(TransformMatrix);
|
|
|
|
BIND_FUNC(module,decor_get_bounds);
|
|
BIND_FUNC(module,decor_render);
|
|
BIND_FUNC(module,decor_handle_event);
|
|
BIND_FUNC(module,decor_show_default_menu);
|
|
|
|
BIND_FUNC(module,rgb);
|
|
|
|
BIND_FUNC(module,draw_button);
|
|
BIND_FUNC(module,fswait);
|
|
}
|