diff options
Diffstat (limited to 'src/libui_sdl/libui/unix')
43 files changed, 0 insertions, 6307 deletions
diff --git a/src/libui_sdl/libui/unix/CMakeLists.txt b/src/libui_sdl/libui/unix/CMakeLists.txt deleted file mode 100644 index c69081e..0000000 --- a/src/libui_sdl/libui/unix/CMakeLists.txt +++ /dev/null @@ -1,87 +0,0 @@ -# 3 june 2016 - -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED gtk+-3.0) - -list(APPEND _LIBUI_SOURCES - unix/alloc.c - unix/area.c - unix/box.c - unix/button.c - unix/cellrendererbutton.c - unix/checkbox.c - unix/child.c - unix/colorbutton.c - unix/combobox.c - unix/control.c - unix/datetimepicker.c - unix/debug.c - unix/draw.c - unix/drawmatrix.c - unix/drawpath.c - unix/drawtext.c - unix/editablecombo.c - unix/entry.c - unix/fontbutton.c - unix/form.c - unix/future.c - unix/graphemes.c - unix/grid.c - unix/group.c - unix/image.c - unix/label.c - unix/main.c - unix/menu.c - unix/multilineentry.c - unix/progressbar.c - unix/radiobuttons.c - unix/separator.c - unix/slider.c - unix/spinbox.c - unix/stddialogs.c - unix/tab.c - unix/text.c - unix/util.c - unix/window.c - unix/gl.c -) -set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) - -list(APPEND _LIBUI_INCLUDEDIRS - unix -) -set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) - -set(_LIBUINAME libui PARENT_SCOPE) -if(NOT BUILD_SHARED_LIBS) - set(_LIBUINAME libui-temporary PARENT_SCOPE) -endif() -macro(_handle_static) - set_target_properties(${_LIBUINAME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") - set(_aname $<TARGET_FILE:${_LIBUINAME}>) - set(_oname libui-combined.o) - add_custom_command( - OUTPUT ${_oname} - DEPENDS ${_LIBUINAME} - COMMAND - ld -r --whole-archive ${_aname} -o ${_oname} - COMMAND - objcopy --localize-hidden ${_oname} - COMMENT "Removing hidden symbols") - add_library(libui STATIC ${_oname}) - # otherwise cmake won't know which linker to use - set_target_properties(libui PROPERTIES - LINKER_LANGUAGE C) - set(_aname) - set(_oname) -endmacro() - -# TODO the other variables don't work? -set(_LIBUI_CFLAGS - ${GTK_CFLAGS} -PARENT_SCOPE) - -set(_LIBUI_LIBS - ${GTK_LDFLAGS} m ${CMAKE_DL_LIBS} -PARENT_SCOPE) diff --git a/src/libui_sdl/libui/unix/alloc.c b/src/libui_sdl/libui/unix/alloc.c deleted file mode 100644 index 2561efa..0000000 --- a/src/libui_sdl/libui/unix/alloc.c +++ /dev/null @@ -1,84 +0,0 @@ -// 7 april 2015 -#include <string.h> -#include "uipriv_unix.h" - -static GPtrArray *allocations; - -#define UINT8(p) ((uint8_t *) (p)) -#define PVOID(p) ((void *) (p)) -#define EXTRA (sizeof (size_t) + sizeof (const char **)) -#define DATA(p) PVOID(UINT8(p) + EXTRA) -#define BASE(p) PVOID(UINT8(p) - EXTRA) -#define SIZE(p) ((size_t *) (p)) -#define CCHAR(p) ((const char **) (p)) -#define TYPE(p) CCHAR(UINT8(p) + sizeof (size_t)) - -void initAlloc(void) -{ - allocations = g_ptr_array_new(); -} - -static void uninitComplain(gpointer ptr, gpointer data) -{ - char **str = (char **) data; - char *str2; - - if (*str == NULL) - *str = g_strdup_printf(""); - str2 = g_strdup_printf("%s%p %s\n", *str, ptr, *TYPE(ptr)); - g_free(*str); - *str = str2; -} - -void uninitAlloc(void) -{ - char *str = NULL; - - if (allocations->len == 0) { - g_ptr_array_free(allocations, TRUE); - return; - } - g_ptr_array_foreach(allocations, uninitComplain, &str); - userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", str); - g_free(str); -} - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = g_malloc0(EXTRA + size); - *SIZE(out) = size; - *TYPE(out) = type; - g_ptr_array_add(allocations, out); - return DATA(out); -} - -void *uiRealloc(void *p, size_t new, const char *type) -{ - void *out; - size_t *s; - - if (p == NULL) - return uiAlloc(new, type); - p = BASE(p); - out = g_realloc(p, EXTRA + new); - s = SIZE(out); - if (new <= *s) - memset(((uint8_t *) DATA(out)) + *s, 0, new - *s); - *s = new; - if (g_ptr_array_remove(allocations, p) == FALSE) - implbug("%p not found in allocations array in uiRealloc()", p); - g_ptr_array_add(allocations, out); - return DATA(out); -} - -void uiFree(void *p) -{ - if (p == NULL) - implbug("attempt to uiFree(NULL)"); - p = BASE(p); - g_free(p); - if (g_ptr_array_remove(allocations, p) == FALSE) - implbug("%p not found in allocations array in uiFree()", p); -} diff --git a/src/libui_sdl/libui/unix/area.c b/src/libui_sdl/libui/unix/area.c deleted file mode 100644 index 5734b4b..0000000 --- a/src/libui_sdl/libui/unix/area.c +++ /dev/null @@ -1,853 +0,0 @@ -// 4 september 2015 -#include "uipriv_unix.h" - -extern GThread* gtkthread; - -// notes: -// - G_DECLARE_DERIVABLE/FINAL_INTERFACE() requires glib 2.44 and that's starting with debian stretch (testing) (GTK+ 3.18) and ubuntu 15.04 (GTK+ 3.14) - debian jessie has 2.42 (GTK+ 3.14) -#define areaWidgetType (areaWidget_get_type()) -#define areaWidget(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), areaWidgetType, areaWidget)) -#define isAreaWidget(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), areaWidgetType)) -#define areaWidgetClass(class) (G_TYPE_CHECK_CLASS_CAST((class), areaWidgetType, areaWidgetClass)) -#define isAreaWidgetClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), areaWidget)) -#define getAreaWidgetClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), areaWidgetType, areaWidgetClass)) - -typedef struct areaWidget areaWidget; -typedef struct areaWidgetClass areaWidgetClass; - -struct areaWidget { - GtkDrawingArea parent_instance; - uiArea *a; - // construct-only parameters aare not set until after the init() function has returned - // we need this particular object available during init(), so put it here instead of in uiArea - // keep a pointer in uiArea for convenience, though - clickCounter cc; -}; - -struct areaWidgetClass { - GtkDrawingAreaClass parent_class; -}; - -typedef struct uiGLContext uiGLContext; - -struct uiArea { - uiUnixControl c; - GtkWidget *widget; // either swidget or areaWidget depending on whether it is scrolling - - GtkWidget *swidget; - GtkContainer *scontainer; - GtkScrolledWindow *sw; - - GtkWidget *areaWidget; - GtkDrawingArea *drawingArea; - areaWidget *area; - - gboolean opengl; - uiGLContext *glContext; - unsigned int* req_versions; - - int bgR, bgG, bgB; - - uiAreaHandler *ah; - - gboolean scrolling; - int scrollWidth; - int scrollHeight; - - // note that this is a pointer; see above - clickCounter *cc; - - // for user window drags - GdkEventButton *dragevent; -}; - -G_DEFINE_TYPE(areaWidget, areaWidget, GTK_TYPE_DRAWING_AREA) - -int boub(GtkWidget* w) { return isAreaWidget(w); } -void baba(GtkWidget* w) -{ - if (!isAreaWidget(w)) return; - - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - if (!a->opengl) return; - - GdkGLContext* oldctx = gdk_gl_context_get_current(); - uiGLMakeContextCurrent(a->glContext); - glFinish(); - gdk_gl_context_make_current(oldctx); -} - -static void areaWidget_init(areaWidget *aw) -{ - // for events - gtk_widget_add_events(GTK_WIDGET(aw), - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - gtk_widget_set_can_focus(GTK_WIDGET(aw), TRUE); - - clickCounterReset(&(aw->cc)); -} - -static void areaWidget_dispose(GObject *obj) -{ - // remove any draw order that might still be pending - areaWidget *aw = areaWidget(obj); - while (g_idle_remove_by_data(aw->a)); - - G_OBJECT_CLASS(areaWidget_parent_class)->dispose(obj); -} - -static void areaWidget_finalize(GObject *obj) -{ - G_OBJECT_CLASS(areaWidget_parent_class)->finalize(obj); -} - -static void areaWidget_size_allocate(GtkWidget *w, GtkAllocation *allocation) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - // GtkDrawingArea has a size_allocate() implementation; we need to call it - // this will call gtk_widget_set_allocation() for us - GTK_WIDGET_CLASS(areaWidget_parent_class)->size_allocate(w, allocation); - - if (!a->scrolling) - // we must redraw everything on resize because Windows requires it - gtk_widget_queue_resize(w); - - a->ah->Resize(a->ah, a, allocation->width, allocation->height); -} - -static void loadAreaSize(uiArea *a, double *width, double *height) -{ - GtkAllocation allocation; - - *width = 0; - *height = 0; - // don't provide size information for scrolling areas - if (!a->scrolling) { - gtk_widget_get_allocation(a->areaWidget, &allocation); - // these are already in drawing space coordinates - // for drawing, the size of drawing space has the same value as the widget allocation - // thanks to tristan in irc.gimp.net/#gtk+ - *width = allocation.width; - *height = allocation.height; - } -} - -static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - uiAreaDrawParams dp; - double clipX0, clipY0, clipX1, clipY1; - - dp.Context = newContext(cr); - - loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight)); - - if (!a->opengl) - { - cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1); - dp.ClipX = clipX0; - dp.ClipY = clipY0; - dp.ClipWidth = clipX1 - clipX0; - dp.ClipHeight = clipY1 - clipY0; - - if (a->bgR != -1) - { - cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0); - cairo_paint(cr); - } - - // no need to save or restore the graphics state to reset transformations; GTK+ does that for us - (*(a->ah->Draw))(a->ah, a, &dp); - } - else - { - areaDrawGL(w, &dp, cr, a->glContext); - } - - freeContext(dp.Context); - return FALSE; -} - -// to do this properly for scrolling areas, we need to -// - return the same value for min and nat -// - call gtk_widget_queue_resize() when the size changes -// thanks to Company in irc.gimp.net/#gtk+ -static void areaWidget_get_preferred_height(GtkWidget *w, gint *min, gint *nat) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - // always chain up just in case - GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_height(w, min, nat); - if (a->scrolling) { - *min = a->scrollHeight; - *nat = a->scrollHeight; - } - - // TODO: min size -} - -static void areaWidget_get_preferred_width(GtkWidget *w, gint *min, gint *nat) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - // always chain up just in case - GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_width(w, min, nat); - if (a->scrolling) { - *min = a->scrollWidth; - *nat = a->scrollWidth; - } -} - -static guint translateModifiers(guint state, GdkWindow *window) -{ - GdkModifierType statetype; - - // GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+) - statetype = state; - gdk_keymap_add_virtual_modifiers( - gdk_keymap_get_for_display(gdk_window_get_display(window)), - &statetype); - return statetype; -} - -static uiModifiers toModifiers(guint state) -{ - uiModifiers m; - - m = 0; - if ((state & GDK_CONTROL_MASK) != 0) - m |= uiModifierCtrl; - if ((state & GDK_META_MASK) != 0) - m |= uiModifierAlt; - if ((state & GDK_MOD1_MASK) != 0) // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c) - m |= uiModifierAlt; - if ((state & GDK_SHIFT_MASK) != 0) - m |= uiModifierShift; - if ((state & GDK_SUPER_MASK) != 0) - m |= uiModifierSuper; - return m; -} - -// capture on drag is done automatically on GTK+ -static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble x, gdouble y, guint state, GdkWindow *window) -{ - // on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake - if (mb >= 4 && mb <= 7) - return; - // if the button ID >= 8, continue counting from 4, as in the MouseEvent spec - if (me->Down >= 8) - me->Down -= 4; - if (me->Up >= 8) - me->Up -= 4; - - state = translateModifiers(state, window); - me->Modifiers = toModifiers(state); - - // the mb != # checks exclude the Up/Down button from Held - me->Held1To64 = 0; - if (mb != 1 && (state & GDK_BUTTON1_MASK) != 0) - me->Held1To64 |= 1 << 0; - if (mb != 2 && (state & GDK_BUTTON2_MASK) != 0) - me->Held1To64 |= 1 << 1; - if (mb != 3 && (state & GDK_BUTTON3_MASK) != 0) - me->Held1To64 |= 1 << 2; - // don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those are for the scrolling buttons mentioned above - // GDK expressly does not support any more buttons in the GdkModifierType; see https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763 (thanks mclasen in irc.gimp.net/#gtk+) - - // these are already in drawing space coordinates - // the size of drawing space has the same value as the widget allocation - // thanks to tristan in irc.gimp.net/#gtk+ - me->X = x; - me->Y = y; - - loadAreaSize(a, &(me->AreaWidth), &(me->AreaHeight)); - - (*(a->ah->MouseEvent))(a->ah, a, me); -} - -static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - gint maxTime, maxDistance; - GtkSettings *settings; - uiAreaMouseEvent me; - - // clicking doesn't automatically transfer keyboard focus; we must do so manually (thanks tristan in irc.gimp.net/#gtk+) - gtk_widget_grab_focus(w); - - // we handle multiple clicks ourselves here, in the same way as we do on Windows - if (e->type != GDK_BUTTON_PRESS) - // ignore GDK's generated double-clicks and beyond - return GDK_EVENT_PROPAGATE; - settings = gtk_widget_get_settings(w); - g_object_get(settings, - "gtk-double-click-time", &maxTime, - "gtk-double-click-distance", &maxDistance, - NULL); - // don't unref settings; it's transfer-none (thanks gregier in irc.gimp.net/#gtk+) - // e->time is guint32 - // e->x and e->y are floating-point; just make them 32-bit integers - // maxTime and maxDistance... are gint, which *should* fit, hopefully... - me.Count = clickCounterClick(a->cc, me.Down, - e->x, e->y, - e->time, maxTime, - maxDistance, maxDistance); - - me.Down = e->button; - me.Up = 0; - - // and set things up for window drags - a->dragevent = e; - finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); - a->dragevent = NULL; - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_button_release_event(GtkWidget *w, GdkEventButton *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - uiAreaMouseEvent me; - - me.Down = 0; - me.Up = e->button; - me.Count = 0; - finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_motion_notify_event(GtkWidget *w, GdkEventMotion *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - uiAreaMouseEvent me; - - me.Down = 0; - me.Up = 0; - me.Count = 0; - finishMouseEvent(a, &me, 0, e->x, e->y, e->state, e->window); - return GDK_EVENT_PROPAGATE; -} - -// we want switching away from the control to reset the double-click counter, like with WM_ACTIVATE on Windows -// according to tristan in irc.gimp.net/#gtk+, doing this on both enter-notify-event and leave-notify-event is correct (and it seems to be true in my own tests; plus the events DO get sent when switching programs with the keyboard (just pointing that out)) -static gboolean onCrossing(areaWidget *aw, int left) -{ - uiArea *a = aw->a; - - (*(a->ah->MouseCrossed))(a->ah, a, left); - clickCounterReset(a->cc); - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_enter_notify_event(GtkWidget *w, GdkEventCrossing *e) -{ - return onCrossing(areaWidget(w), 0); -} - -static gboolean areaWidget_leave_notify_event(GtkWidget *w, GdkEventCrossing *e) -{ - return onCrossing(areaWidget(w), 1); -} - -// note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally is no way to break a grab like that (at least not on X11 and Wayland) -// even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons -// therefore, no DragBroken() - -// we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user - -static const struct { - guint keyval; - uiExtKey extkey; -} extKeys[] = { - { GDK_KEY_Escape, uiExtKeyEscape }, - { GDK_KEY_Insert, uiExtKeyInsert }, - { GDK_KEY_Delete, uiExtKeyDelete }, - { GDK_KEY_Home, uiExtKeyHome }, - { GDK_KEY_End, uiExtKeyEnd }, - { GDK_KEY_Page_Up, uiExtKeyPageUp }, - { GDK_KEY_Page_Down, uiExtKeyPageDown }, - { GDK_KEY_Up, uiExtKeyUp }, - { GDK_KEY_Down, uiExtKeyDown }, - { GDK_KEY_Left, uiExtKeyLeft }, - { GDK_KEY_Right, uiExtKeyRight }, - { GDK_KEY_F1, uiExtKeyF1 }, - { GDK_KEY_F2, uiExtKeyF2 }, - { GDK_KEY_F3, uiExtKeyF3 }, - { GDK_KEY_F4, uiExtKeyF4 }, - { GDK_KEY_F5, uiExtKeyF5 }, - { GDK_KEY_F6, uiExtKeyF6 }, - { GDK_KEY_F7, uiExtKeyF7 }, - { GDK_KEY_F8, uiExtKeyF8 }, - { GDK_KEY_F9, uiExtKeyF9 }, - { GDK_KEY_F10, uiExtKeyF10 }, - { GDK_KEY_F11, uiExtKeyF11 }, - { GDK_KEY_F12, uiExtKeyF12 }, - // numpad numeric keys and . are handled in events.c - { GDK_KEY_KP_Enter, uiExtKeyNEnter }, - { GDK_KEY_KP_Add, uiExtKeyNAdd }, - { GDK_KEY_KP_Subtract, uiExtKeyNSubtract }, - { GDK_KEY_KP_Multiply, uiExtKeyNMultiply }, - { GDK_KEY_KP_Divide, uiExtKeyNDivide }, - { GDK_KEY_Print, 0 }, -}; - -static const struct { - guint keyval; - uiModifiers mod; -} modKeys[] = { - { GDK_KEY_Control_L, uiModifierCtrl }, - { GDK_KEY_Control_R, uiModifierCtrl }, - { GDK_KEY_Alt_L, uiModifierAlt }, - { GDK_KEY_Alt_R, uiModifierAlt }, - { GDK_KEY_Meta_L, uiModifierAlt }, - { GDK_KEY_Meta_R, uiModifierAlt }, - { GDK_KEY_Shift_L, uiModifierShift }, - { GDK_KEY_Shift_R, uiModifierShift }, - { GDK_KEY_Super_L, uiModifierSuper }, - { GDK_KEY_Super_R, uiModifierSuper }, - { GDK_KEY_Print, 0 }, -}; - -// http://www.comptechdoc.org/os/linux/howlinuxworks/linux_hlkeycodes.html -int scancode_unix2normal(int scan) -{ - scan -= 8; - - // extended keys get weird scancodes. fix 'em up - switch (scan) - { - case 0x60: return 0x11C; - case 0x61: return 0x11D; - case 0x62: return 0x135; - case 0x63: return 0x137; - case 0x64: return 0x138; - case 0x66: return 0x147; - case 0x67: return 0x148; - case 0x68: return 0x149; - case 0x69: return 0x14B; - case 0x6A: return 0x14D; - case 0x6B: return 0x14F; - case 0x6C: return 0x150; - case 0x6D: return 0x151; - case 0x6E: return 0x152; - case 0x6F: return 0x153; - case 0x77: return 0x45; // PAUSE, this one is weird. check it. - case 0x7D: return 0x15B; // Windows key - case 0x7F: return 0x15D; // context menu key - // TODO: there may be more fancy keys - default: return scan; - } -} - -int scancode_normal2unix(int scan) -{ - // extended keys get weird scancodes. fix 'em up - switch (scan) - { - case 0x11C: return 8+0x60; - case 0x11D: return 8+0x61; - case 0x135: return 8+0x62; - case 0x137: return 8+0x63; - case 0x138: return 8+0x64; - case 0x147: return 8+0x66; - case 0x148: return 8+0x67; - case 0x149: return 8+0x68; - case 0x14B: return 8+0x69; - case 0x14D: return 8+0x6A; - case 0x14F: return 8+0x6B; - case 0x150: return 8+0x6C; - case 0x151: return 8+0x6D; - case 0x152: return 8+0x6E; - case 0x153: return 8+0x6F; - case 0x45: return 8+0x77; // PAUSE, this one is weird. check it. - case 0x15B: return 8+0x7D; // Windows key - case 0x15D: return 8+0x7F; // context menu key - // TODO: there may be more fancy keys - default: return scan + 8; - } -} - -static int areaKeyEvent(uiArea *a, int up, GdkEventKey *e) -{ - uiAreaKeyEvent ke; - guint state; - int i; - - ke.Key = 0; - ke.ExtKey = 0; - ke.Modifier = 0; - - state = translateModifiers(e->state, e->window); - ke.Modifiers = toModifiers(state); - - ke.Up = up; - ke.Repeat = 0; // TODO!!!!! - - ke.Scancode = scancode_unix2normal(e->hardware_keycode); - -#if 0 - for (i = 0; extKeys[i].keyval != GDK_KEY_Print; i++) - if (extKeys[i].keyval == e->keyval) { - ke.ExtKey = extKeys[i].extkey; - goto keyFound; - } - - for (i = 0; modKeys[i].keyval != GDK_KEY_Print; i++) - if (modKeys[i].keyval == e->keyval) { - ke.Modifier = modKeys[i].mod; - // don't include the modifier in ke.Modifiers - ke.Modifiers &= ~ke.Modifier; - goto keyFound; - } - - if (fromScancode(e->hardware_keycode - 8, &ke)) - goto keyFound; - - // no supported key found; treat as unhandled - return 0; - -keyFound: -#endif - return (*(a->ah->KeyEvent))(a->ah, a, &ke); -} - -static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - if (areaKeyEvent(a, 0, e)) - return GDK_EVENT_STOP; - return GDK_EVENT_PROPAGATE; -} - -static gboolean areaWidget_key_release_event(GtkWidget *w, GdkEventKey *e) -{ - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - - if (areaKeyEvent(a, 1, e)) - return GDK_EVENT_STOP; - return GDK_EVENT_PROPAGATE; -} - -char* uiKeyName(int scancode) -{ - scancode = scancode_normal2unix(scancode); - - char* ret; - guint* keyvals; int num; - GdkKeymap* keymap = gdk_keymap_get_for_display(gdk_display_get_default()); - if (gdk_keymap_get_entries_for_keycode(keymap, scancode, NULL, &keyvals, &num)) - { - // TODO: pick smarter?? - int keyval = keyvals[0]; - - g_free(keyvals); - - ret = gdk_keyval_name(keyval); - } - else - { - char tmp[16]; - sprintf(tmp, "#%03X", scancode); - ret = tmp; - } - - return uiUnixStrdupText(ret); -} - -enum { - pArea = 1, - nProps, -}; - -static GParamSpec *pspecArea; - -static void areaWidget_set_property(GObject *obj, guint prop, const GValue *value, GParamSpec *pspec) -{ - areaWidget *aw = areaWidget(obj); - - switch (prop) { - case pArea: - aw->a = (uiArea *) g_value_get_pointer(value); - aw->a->cc = &(aw->cc); - return; - } - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec); -} - -static void areaWidget_get_property(GObject *obj, guint prop, GValue *value, GParamSpec *pspec) -{ - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec); -} - -static void areaWidget_class_init(areaWidgetClass *class) -{ - G_OBJECT_CLASS(class)->dispose = areaWidget_dispose; - G_OBJECT_CLASS(class)->finalize = areaWidget_finalize; - G_OBJECT_CLASS(class)->set_property = areaWidget_set_property; - G_OBJECT_CLASS(class)->get_property = areaWidget_get_property; - - GTK_WIDGET_CLASS(class)->size_allocate = areaWidget_size_allocate; - GTK_WIDGET_CLASS(class)->draw = areaWidget_draw; - GTK_WIDGET_CLASS(class)->get_preferred_height = areaWidget_get_preferred_height; - GTK_WIDGET_CLASS(class)->get_preferred_width = areaWidget_get_preferred_width; - GTK_WIDGET_CLASS(class)->button_press_event = areaWidget_button_press_event; - GTK_WIDGET_CLASS(class)->button_release_event = areaWidget_button_release_event; - GTK_WIDGET_CLASS(class)->motion_notify_event = areaWidget_motion_notify_event; - GTK_WIDGET_CLASS(class)->enter_notify_event = areaWidget_enter_notify_event; - GTK_WIDGET_CLASS(class)->leave_notify_event = areaWidget_leave_notify_event; - GTK_WIDGET_CLASS(class)->key_press_event = areaWidget_key_press_event; - GTK_WIDGET_CLASS(class)->key_release_event = areaWidget_key_release_event; - - pspecArea = g_param_spec_pointer("libui-area", - "libui-area", - "uiArea.", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property(G_OBJECT_CLASS(class), pArea, pspecArea); -} - -// control implementation - -uiUnixControlAllDefaultsExceptDestroy(uiArea) - -static void uiAreaDestroy(uiControl *c) -{ - uiArea* a = uiArea(c); - if (a->opengl && a->glContext) freeGLContext(a->glContext); - g_object_unref(uiArea(c)->widget); - uiFreeControl(c); -} - -void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b) -{ - a->bgR = r; - a->bgG = g; - a->bgB = b; -} - -void uiAreaSetSize(uiArea *a, int width, int height) -{ - if (!a->scrolling) - userbug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (area: %p)", a); - a->scrollWidth = width; - a->scrollHeight = height; - gtk_widget_queue_resize(a->areaWidget); -} - -gboolean _threadsaferefresh(gpointer data) -{ - uiArea* a = (uiArea*)data; - gtk_widget_queue_draw(a->areaWidget); - return FALSE; -} - -void uiAreaQueueRedrawAll(uiArea *a) -{ - // TODO: figure out how we could generalize the "thread-safe function call" mechanism - if (g_thread_self() != gtkthread) - g_idle_add(_threadsaferefresh, a); - else - gtk_widget_queue_draw(a->areaWidget); -} - -void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) -{ - // TODO - // TODO adjust adjustments and find source for that -} - -void uiAreaBeginUserWindowMove(uiArea *a) -{ - GtkWidget *toplevel; - - if (a->dragevent == NULL) - userbug("cannot call uiAreaBeginUserWindowMove() outside of a Mouse() with Down != 0"); - // TODO don't we have a libui function for this? did I scrap it? - // TODO widget or areaWidget? - toplevel = gtk_widget_get_toplevel(a->widget); - if (toplevel == NULL) { - // TODO - return; - } - // the docs say to do this - if (!gtk_widget_is_toplevel(toplevel)) { - // TODO - return; - } - if (!GTK_IS_WINDOW(toplevel)) { - // TODO - return; - } - gtk_window_begin_move_drag(GTK_WINDOW(toplevel), - a->dragevent->button, - a->dragevent->x_root, // TODO are these correct? - a->dragevent->y_root, - a->dragevent->time); -} - -static const GdkWindowEdge edges[] = { - [uiWindowResizeEdgeLeft] = GDK_WINDOW_EDGE_WEST, - [uiWindowResizeEdgeTop] = GDK_WINDOW_EDGE_NORTH, - [uiWindowResizeEdgeRight] = GDK_WINDOW_EDGE_EAST, - [uiWindowResizeEdgeBottom] = GDK_WINDOW_EDGE_SOUTH, - [uiWindowResizeEdgeTopLeft] = GDK_WINDOW_EDGE_NORTH_WEST, - [uiWindowResizeEdgeTopRight] = GDK_WINDOW_EDGE_NORTH_EAST, - [uiWindowResizeEdgeBottomLeft] = GDK_WINDOW_EDGE_SOUTH_WEST, - [uiWindowResizeEdgeBottomRight] = GDK_WINDOW_EDGE_SOUTH_EAST, -}; - -void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) -{ - GtkWidget *toplevel; - - if (a->dragevent == NULL) - userbug("cannot call uiAreaBeginUserWindowResize() outside of a Mouse() with Down != 0"); - // TODO don't we have a libui function for this? did I scrap it? - // TODO widget or areaWidget? - toplevel = gtk_widget_get_toplevel(a->widget); - if (toplevel == NULL) { - // TODO - return; - } - // the docs say to do this - if (!gtk_widget_is_toplevel(toplevel)) { - // TODO - return; - } - if (!GTK_IS_WINDOW(toplevel)) { - // TODO - return; - } - gtk_window_begin_resize_drag(GTK_WINDOW(toplevel), - edges[edge], - a->dragevent->button, - a->dragevent->x_root, // TODO are these correct? - a->dragevent->y_root, - a->dragevent->time); -} - -uiArea *uiNewArea(uiAreaHandler *ah) -{ - uiArea *a; - - uiUnixNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = FALSE; - a->opengl = FALSE; - - a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, - "libui-area", a, - NULL)); - a->drawingArea = GTK_DRAWING_AREA(a->areaWidget); - a->area = areaWidget(a->areaWidget); - - a->widget = a->areaWidget; - - uiAreaSetBackgroundColor(a, -1, -1, -1); - - return a; -} - -void _areaCreateGLContext(GtkWidget* widget, gpointer data) -{ - uiArea* a = (uiArea*)data; - - uiGLContext* ctx = NULL; - for (int i = 0; a->req_versions[i] && !ctx; i++) - { - int major = uiGLVerMajor(a->req_versions[i]); - int minor = uiGLVerMinor(a->req_versions[i]); - - // we cannot support any version older than 3.2 via GDK - if ((major < 3) || (major == 3 && minor < 2)) - break; - - ctx = createGLContext(widget, major, minor); - } - - a->glContext = ctx; -} - -uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions) -{ - uiArea *a; - - uiUnixNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = FALSE; - a->opengl = TRUE; - - a->glContext = NULL; - a->req_versions = req_versions; - a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, - "libui-area", a, - NULL)); - a->area = areaWidget(a->areaWidget); - - a->widget = a->areaWidget; - - g_signal_connect(a->widget, "realize", G_CALLBACK(_areaCreateGLContext), a); - - uiAreaSetBackgroundColor(a, -1, -1, -1); - - return a; -} - -uiGLContext *uiAreaGetGLContext(uiArea* a) -{ - if (!a) return NULL; - return a->glContext; -} - -uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) -{ - uiArea *a; - - uiUnixNewControl(uiArea, a); - - a->ah = ah; - a->scrolling = TRUE; - a->scrollWidth = width; - a->scrollHeight = height; - a->opengl = FALSE; - - a->swidget = gtk_scrolled_window_new(NULL, NULL); - a->scontainer = GTK_CONTAINER(a->swidget); - a->sw = GTK_SCROLLED_WINDOW(a->swidget); - - a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, - "libui-area", a, - NULL)); - a->drawingArea = GTK_DRAWING_AREA(a->areaWidget); - a->area = areaWidget(a->areaWidget); - - a->widget = a->swidget; - - uiAreaSetBackgroundColor(a, -1, -1, -1); - - gtk_container_add(a->scontainer, a->areaWidget); - // and make the area visible; only the scrolled window's visibility is controlled by libui - gtk_widget_show(a->areaWidget); - - return a; -} diff --git a/src/libui_sdl/libui/unix/box.c b/src/libui_sdl/libui/unix/box.c deleted file mode 100644 index 23fb7f7..0000000 --- a/src/libui_sdl/libui/unix/box.c +++ /dev/null @@ -1,159 +0,0 @@ -// 7 april 2015 -#include "uipriv_unix.h" - -struct boxChild { - uiControl *c; - int stretchy; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; -}; - -struct uiBox { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBox *box; - GArray *controls; - int vertical; - int padded; - GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size -}; - -uiUnixControlAllDefaultsExceptDestroy(uiBox) - -#define ctrl(b, i) &g_array_index(b->controls, struct boxChild, i) - -static void uiBoxDestroy(uiControl *c) -{ - uiBox *b = uiBox(c); - struct boxChild *bc; - guint i; - - // kill the size group - g_object_unref(b->stretchygroup); - // free all controls - for (i = 0; i < b->controls->len; i++) { - bc = ctrl(b, i); - uiControlSetParent(bc->c, NULL); - // and make sure the widget itself stays alive - uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); - uiControlDestroy(bc->c); - } - g_array_free(b->controls, TRUE); - // and then ourselves - g_object_unref(b->widget); - uiFreeControl(uiControl(b)); -} - -void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) -{ - struct boxChild bc; - GtkWidget *widget; - - bc.c = c; - bc.stretchy = stretchy; - widget = GTK_WIDGET(uiControlHandle(bc.c)); - bc.oldhexpand = gtk_widget_get_hexpand(widget); - bc.oldhalign = gtk_widget_get_halign(widget); - bc.oldvexpand = gtk_widget_get_vexpand(widget); - bc.oldvalign = gtk_widget_get_valign(widget); - - if (bc.stretchy) { - if (b->vertical) { - gtk_widget_set_vexpand(widget, TRUE); - gtk_widget_set_valign(widget, GTK_ALIGN_FILL); - } else { - gtk_widget_set_hexpand(widget, TRUE); - gtk_widget_set_halign(widget, GTK_ALIGN_FILL); - } - gtk_size_group_add_widget(b->stretchygroup, widget); - } else - if (b->vertical) - gtk_widget_set_vexpand(widget, FALSE); - else - gtk_widget_set_hexpand(widget, FALSE); - // and make them fill the opposite direction - if (b->vertical) { - gtk_widget_set_hexpand(widget, TRUE); - gtk_widget_set_halign(widget, GTK_ALIGN_FILL); - } else { - gtk_widget_set_vexpand(widget, TRUE); - gtk_widget_set_valign(widget, GTK_ALIGN_FILL); - } - - uiControlSetParent(bc.c, uiControl(b)); - uiUnixControlSetContainer(uiUnixControl(bc.c), b->container, FALSE); - g_array_append_val(b->controls, bc); -} - -void uiBoxDelete(uiBox *b, int index) -{ - struct boxChild *bc; - GtkWidget *widget; - - bc = ctrl(b, index); - widget = GTK_WIDGET(uiControlHandle(bc->c)); - - uiControlSetParent(bc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); - - if (bc->stretchy) - gtk_size_group_remove_widget(b->stretchygroup, widget); - gtk_widget_set_hexpand(widget, bc->oldhexpand); - gtk_widget_set_halign(widget, bc->oldhalign); - gtk_widget_set_vexpand(widget, bc->oldvexpand); - gtk_widget_set_valign(widget, bc->oldvalign); - - g_array_remove_index(b->controls, index); -} - -int uiBoxPadded(uiBox *b) -{ - return b->padded; -} - -void uiBoxSetPadded(uiBox *b, int padded) -{ - b->padded = padded; - if (b->padded) - if (b->vertical) - gtk_box_set_spacing(b->box, gtkYPadding); - else - gtk_box_set_spacing(b->box, gtkXPadding); - else - gtk_box_set_spacing(b->box, 0); -} - -static uiBox *finishNewBox(GtkOrientation orientation) -{ - uiBox *b; - - uiUnixNewControl(uiBox, b); - - b->widget = gtk_box_new(orientation, 0); - b->container = GTK_CONTAINER(b->widget); - b->box = GTK_BOX(b->widget); - - b->vertical = orientation == GTK_ORIENTATION_VERTICAL; - - if (b->vertical) - b->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); - else - b->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - b->controls = g_array_new(FALSE, TRUE, sizeof (struct boxChild)); - - return b; -} - -uiBox *uiNewHorizontalBox(void) -{ - return finishNewBox(GTK_ORIENTATION_HORIZONTAL); -} - -uiBox *uiNewVerticalBox(void) -{ - return finishNewBox(GTK_ORIENTATION_VERTICAL); -} diff --git a/src/libui_sdl/libui/unix/button.c b/src/libui_sdl/libui/unix/button.c deleted file mode 100644 index b0500e3..0000000 --- a/src/libui_sdl/libui/unix/button.c +++ /dev/null @@ -1,57 +0,0 @@ -// 10 june 2015 -#include "uipriv_unix.h" - -struct uiButton { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -uiUnixControlAllDefaults(uiButton) - -static void onClicked(GtkButton *button, gpointer data) -{ - uiButton *b = uiButton(data); - - (*(b->onClicked))(b, b->onClickedData); -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -char *uiButtonText(uiButton *b) -{ - return uiUnixStrdupText(gtk_button_get_label(b->button)); -} - -void uiButtonSetText(uiButton *b, const char *text) -{ - gtk_button_set_label(b->button, text); -} - -void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) -{ - b->onClicked = f; - b->onClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - uiButton *b; - - uiUnixNewControl(uiButton, b); - - b->widget = gtk_button_new_with_label(text); - b->button = GTK_BUTTON(b->widget); - - g_signal_connect(b->widget, "clicked", G_CALLBACK(onClicked), b); - uiButtonOnClicked(b, defaultOnClicked, NULL); - - gtk_widget_set_size_request(b->widget, 64, 1); - - return b; -} diff --git a/src/libui_sdl/libui/unix/cellrendererbutton.c b/src/libui_sdl/libui/unix/cellrendererbutton.c deleted file mode 100644 index e3bbf48..0000000 --- a/src/libui_sdl/libui/unix/cellrendererbutton.c +++ /dev/null @@ -1,299 +0,0 @@ -// 28 june 2016 -#include "uipriv_unix.h" - -// TODOs -// - it's a rather tight fit -// - selected row text color is white -// - resizing a column with a button in it crashes the program -// - accessibility -// - right side too big? - -#define cellRendererButtonType (cellRendererButton_get_type()) -#define cellRendererButton(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), cellRendererButtonType, cellRendererButton)) -#define isCellRendererButton(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), cellRendererButtonType)) -#define cellRendererButtonClass(class) (G_TYPE_CHECK_CLASS_CAST((class), cellRendererButtonType, cellRendererButtonClass)) -#define isCellRendererButtonClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), cellRendererButton)) -#define getCellRendererButtonClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), cellRendererButtonType, cellRendererButtonClass)) - -typedef struct cellRendererButton cellRendererButton; -typedef struct cellRendererButtonClass cellRendererButtonClass; - -struct cellRendererButton { - GtkCellRenderer parent_instance; - char *text; -}; - -struct cellRendererButtonClass { - GtkCellRendererClass parent_class; -}; - -G_DEFINE_TYPE(cellRendererButton, cellRendererButton, GTK_TYPE_CELL_RENDERER) - -static void cellRendererButton_init(cellRendererButton *c) -{ - g_object_set(c, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); - // the standard cell renderers all do this - gtk_cell_renderer_set_padding(GTK_CELL_RENDERER(c), 2, 2); -} - -static void cellRendererButton_dispose(GObject *obj) -{ - G_OBJECT_CLASS(cellRendererButton_parent_class)->dispose(obj); -} - -static void cellRendererButton_finalize(GObject *obj) -{ - cellRendererButton *c = cellRendererButton(obj); - - if (c->text != NULL) { - g_free(c->text); - c->text = NULL; - } - G_OBJECT_CLASS(cellRendererButton_parent_class)->finalize(obj); -} - -static GtkSizeRequestMode cellRendererButton_get_request_mode(GtkCellRenderer *r) -{ - return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; -} - -// this is basically what GtkCellRendererToggle did in 3.10 and does in 3.20, as well as what the Foreign Drawing gtk3-demo demo does -static GtkStyleContext *setButtonStyle(GtkWidget *widget) -{ - GtkStyleContext *base, *context; - GtkWidgetPath *path; - - base = gtk_widget_get_style_context(widget); - context = gtk_style_context_new(); - - path = gtk_widget_path_copy(gtk_style_context_get_path(base)); - gtk_widget_path_append_type(path, G_TYPE_NONE); - if (!FUTURE_gtk_widget_path_iter_set_object_name(path, -1, "button")) - // not on 3.20; try the type - gtk_widget_path_iter_set_object_type(path, -1, GTK_TYPE_BUTTON); - - gtk_style_context_set_path(context, path); - gtk_style_context_set_parent(context, base); - // the gtk3-demo example (which says we need to do this) uses gtk_widget_path_iter_get_state(path, -1) but that's not available until 3.14 - // TODO make a future for that too - gtk_style_context_set_state(context, gtk_style_context_get_state(base)); - gtk_widget_path_unref(path); - - // and if the above widget path screwery stil doesn't work, this will - gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON); - - return context; -} - -void unsetButtonStyle(GtkStyleContext *context) -{ - g_object_unref(context); -} - -// this is based on what GtkCellRendererText does -static void cellRendererButton_get_preferred_width(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad; - PangoLayout *layout; - PangoRectangle rect; - gint out; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, NULL); - - layout = gtk_widget_create_pango_layout(widget, c->text); - pango_layout_set_width(layout, -1); - pango_layout_get_extents(layout, NULL, &rect); - g_object_unref(layout); - - out = 2 * xpad + PANGO_PIXELS_CEIL(rect.width); - if (minimum != NULL) - *minimum = out; - if (natural != NULL) - *natural = out; -} - -// this is based on what GtkCellRendererText does -static void cellRendererButton_get_preferred_height_for_width(GtkCellRenderer *r, GtkWidget *widget, gint width, gint *minimum, gint *natural) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad, ypad; - PangoLayout *layout; - gint height; - gint out; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad); - - layout = gtk_widget_create_pango_layout(widget, c->text); - pango_layout_set_width(layout, ((2 * xpad + width) * PANGO_SCALE)); - pango_layout_get_pixel_size(layout, NULL, &height); - g_object_unref(layout); - - out = 2 * ypad + height; - if (minimum != NULL) - *minimum = out; - if (natural != NULL) - *natural = out; -} - -// this is basically what GtkCellRendererText does -static void cellRendererButton_get_preferred_height(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural) -{ - gint width; - - gtk_cell_renderer_get_preferred_width(r, widget, &width, NULL); - gtk_cell_renderer_get_preferred_height_for_width(r, widget, width, minimum, natural); -} - -// this is based on what GtkCellRendererText does -static void cellRendererButton_get_aligned_area(GtkCellRenderer *r, GtkWidget *widget, GtkCellRendererState flags, const GdkRectangle *cell_area, GdkRectangle *aligned_area) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad, ypad; - PangoLayout *layout; - PangoRectangle rect; - gfloat xalign, yalign; - gint xoffset, yoffset; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad); - - layout = gtk_widget_create_pango_layout(widget, c->text); - pango_layout_set_width(layout, -1); - pango_layout_get_pixel_extents(layout, NULL, &rect); - - xoffset = 0; - yoffset = 0; - if (cell_area != NULL) { - gtk_cell_renderer_get_alignment(GTK_CELL_RENDERER(c), &xalign, &yalign); - xoffset = cell_area->width - (2 * xpad + rect.width); - // use explicit casts just to be safe - if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL) - xoffset = ((gdouble) xoffset) * (1.0 - xalign); - else - xoffset *= ((gdouble) xoffset) * xalign; - yoffset = yalign * (cell_area->height - (2 * ypad + rect.height)); - yoffset = MAX(yoffset, 0); - } - - aligned_area->x = cell_area->x + xoffset; - aligned_area->y = cell_area->y + yoffset; - aligned_area->width = 2 * xpad + rect.width; - aligned_area->height = 2 * ypad + rect.height; - - g_object_unref(layout); -} - -// this is based on both what GtkCellRendererText does and what GtkCellRendererToggle does -static void cellRendererButton_render(GtkCellRenderer *r, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) -{ - cellRendererButton *c = cellRendererButton(r); - gint xpad, ypad; - GdkRectangle alignedArea; - gint xoffset, yoffset; - GtkStyleContext *context; - PangoLayout *layout; - PangoRectangle rect; - - gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad); - gtk_cell_renderer_get_aligned_area(GTK_CELL_RENDERER(c), widget, flags, cell_area, &alignedArea); - xoffset = alignedArea.x - cell_area->x; - yoffset = alignedArea.y - cell_area->y; - - context = setButtonStyle(widget); - layout = gtk_widget_create_pango_layout(widget, c->text); - - gtk_render_background(context, cr, - background_area->x + xoffset + xpad, - background_area->y + yoffset + ypad, - background_area->width - 2 * xpad, - background_area->height - 2 * ypad); - gtk_render_frame(context, cr, - background_area->x + xoffset + xpad, - background_area->y + yoffset + ypad, - background_area->width - 2 * xpad, - background_area->height - 2 * ypad); - - pango_layout_set_width(layout, -1); - pango_layout_get_pixel_extents(layout, NULL, &rect); - xoffset -= rect.x; - gtk_render_layout(context, cr, - cell_area->x + xoffset + xpad, - cell_area->y + yoffset + ypad, - layout); - - g_object_unref(layout); - unsetButtonStyle(context); -} - -static guint clickedSignal; - -static gboolean cellRendererButton_activate(GtkCellRenderer *r, GdkEvent *e, GtkWidget *widget, const gchar *path, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) -{ - g_signal_emit(r, clickedSignal, 0, path); - return TRUE; -} - -static GParamSpec *props[2] = { NULL, NULL }; - -static void cellRendererButton_set_property(GObject *object, guint prop, const GValue *value, GParamSpec *pspec) -{ - cellRendererButton *c = cellRendererButton(object); - - if (prop != 1) { - G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop, pspec); - return; - } - if (c->text != NULL) - g_free(c->text); - c->text = g_value_dup_string(value); - // GtkCellRendererText doesn't queue a redraw; we won't either -} - -static void cellRendererButton_get_property(GObject *object, guint prop, GValue *value, GParamSpec *pspec) -{ - cellRendererButton *c = cellRendererButton(object); - - if (prop != 1) { - G_OBJECT_WARN_INVALID_PROPERTY_ID(c, prop, pspec); - return; - } - g_value_set_string(value, c->text); -} - -static void cellRendererButton_class_init(cellRendererButtonClass *class) -{ - G_OBJECT_CLASS(class)->dispose = cellRendererButton_dispose; - G_OBJECT_CLASS(class)->finalize = cellRendererButton_finalize; - G_OBJECT_CLASS(class)->set_property = cellRendererButton_set_property; - G_OBJECT_CLASS(class)->get_property = cellRendererButton_get_property; - GTK_CELL_RENDERER_CLASS(class)->get_request_mode = cellRendererButton_get_request_mode; - GTK_CELL_RENDERER_CLASS(class)->get_preferred_width = cellRendererButton_get_preferred_width; - GTK_CELL_RENDERER_CLASS(class)->get_preferred_height_for_width = cellRendererButton_get_preferred_height_for_width; - GTK_CELL_RENDERER_CLASS(class)->get_preferred_height = cellRendererButton_get_preferred_height; - // don't provide a get_preferred_width_for_height() - GTK_CELL_RENDERER_CLASS(class)->get_aligned_area = cellRendererButton_get_aligned_area; - // don't provide a get_size() - GTK_CELL_RENDERER_CLASS(class)->render = cellRendererButton_render; - GTK_CELL_RENDERER_CLASS(class)->activate = cellRendererButton_activate; - // don't provide a start_editing() - - props[1] = g_param_spec_string("text", - "Text", - "Button text", - "", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties(G_OBJECT_CLASS(class), 2, props); - - clickedSignal = g_signal_new("clicked", - G_TYPE_FROM_CLASS(class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, - 1, G_TYPE_STRING); -} - -GtkCellRenderer *newCellRendererButton(void) -{ - return GTK_CELL_RENDERER(g_object_new(cellRendererButtonType, NULL)); -} diff --git a/src/libui_sdl/libui/unix/checkbox.c b/src/libui_sdl/libui/unix/checkbox.c deleted file mode 100644 index 47f8514..0000000 --- a/src/libui_sdl/libui/unix/checkbox.c +++ /dev/null @@ -1,78 +0,0 @@ -// 10 june 2015 -#include "uipriv_unix.h" - -struct uiCheckbox { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - GtkToggleButton *toggleButton; - GtkCheckButton *checkButton; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; - gulong onToggledSignal; -}; - -uiUnixControlAllDefaults(uiCheckbox) - -static void onToggled(GtkToggleButton *b, gpointer data) -{ - uiCheckbox *c = uiCheckbox(data); - - (*(c->onToggled))(c, c->onToggledData); -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -char *uiCheckboxText(uiCheckbox *c) -{ - return uiUnixStrdupText(gtk_button_get_label(c->button)); -} - -void uiCheckboxSetText(uiCheckbox *c, const char *text) -{ - gtk_button_set_label(GTK_BUTTON(c->button), text); -} - -void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *, void *), void *data) -{ - c->onToggled = f; - c->onToggledData = data; -} - -int uiCheckboxChecked(uiCheckbox *c) -{ - return gtk_toggle_button_get_active(c->toggleButton) != FALSE; -} - -void uiCheckboxSetChecked(uiCheckbox *c, int checked) -{ - gboolean active; - - active = FALSE; - if (checked) - active = TRUE; - // we need to inhibit sending of ::toggled because this WILL send a ::toggled otherwise - g_signal_handler_block(c->toggleButton, c->onToggledSignal); - gtk_toggle_button_set_active(c->toggleButton, active); - g_signal_handler_unblock(c->toggleButton, c->onToggledSignal); -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - uiCheckbox *c; - - uiUnixNewControl(uiCheckbox, c); - - c->widget = gtk_check_button_new_with_label(text); - c->button = GTK_BUTTON(c->widget); - c->toggleButton = GTK_TOGGLE_BUTTON(c->widget); - c->checkButton = GTK_CHECK_BUTTON(c->widget); - - c->onToggledSignal = g_signal_connect(c->widget, "toggled", G_CALLBACK(onToggled), c); - uiCheckboxOnToggled(c, defaultOnToggled, NULL); - - return c; -} diff --git a/src/libui_sdl/libui/unix/child.c b/src/libui_sdl/libui/unix/child.c deleted file mode 100644 index b4a0967..0000000 --- a/src/libui_sdl/libui/unix/child.c +++ /dev/null @@ -1,120 +0,0 @@ -// 28 august 2015 -#include "uipriv_unix.h" - -// This file contains helpers for managing child controls. - -struct child { - uiControl *c; - GtkWidget *widget; - - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; - - // Some children can be boxed; that is, they can have an optionally-margined box around them. - // uiGroup, uiTab, and uiWindow all do this. - GtkWidget *box; - - // If the child is not boxed, this is its parent. - // If the child is boxed, this is the box. - GtkContainer *parent; - - // This flag is for users of these functions. - // For uiBox, this is "spaced". - // For uiTab, this is "margined". (uiGroup and uiWindow have to maintain their margined state themselves, since the margined state is independent of whether there is a child for those two.) - int flag; -}; - -struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer) -{ - struct child *c; - - if (child == NULL) - return NULL; - - c = uiNew(struct child); - c->c = child; - c->widget = GTK_WIDGET(uiControlHandle(c->c)); - - c->oldhexpand = gtk_widget_get_hexpand(c->widget); - c->oldhalign = gtk_widget_get_halign(c->widget); - c->oldvexpand = gtk_widget_get_vexpand(c->widget); - c->oldvalign = gtk_widget_get_valign(c->widget); - - uiControlSetParent(c->c, parent); - uiUnixControlSetContainer(uiUnixControl(c->c), parentContainer, FALSE); - c->parent = parentContainer; - - return c; -} - -struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined) -{ - struct child *c; - GtkWidget *box; - - if (child == NULL) - return NULL; - box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_show(box); - c = newChild(child, parent, GTK_CONTAINER(box)); - gtk_widget_set_hexpand(c->widget, TRUE); - gtk_widget_set_halign(c->widget, GTK_ALIGN_FILL); - gtk_widget_set_vexpand(c->widget, TRUE); - gtk_widget_set_valign(c->widget, GTK_ALIGN_FILL); - c->box = box; - gtk_container_add(parentContainer, c->box); - childSetMargined(c, margined); - return c; -} - -void childRemove(struct child *c) -{ - uiControlSetParent(c->c, NULL); - uiUnixControlSetContainer(uiUnixControl(c->c), c->parent, TRUE); - - gtk_widget_set_hexpand(c->widget, c->oldhexpand); - gtk_widget_set_halign(c->widget, c->oldhalign); - gtk_widget_set_vexpand(c->widget, c->oldvexpand); - gtk_widget_set_valign(c->widget, c->oldvalign); - - if (c->box != NULL) - gtk_widget_destroy(c->box); - - uiFree(c); -} - -void childDestroy(struct child *c) -{ - uiControl *child; - - child = c->c; - childRemove(c); - uiControlDestroy(child); -} - -GtkWidget *childWidget(struct child *c) -{ - return c->widget; -} - -int childFlag(struct child *c) -{ - return c->flag; -} - -void childSetFlag(struct child *c, int flag) -{ - c->flag = flag; -} - -GtkWidget *childBox(struct child *c) -{ - return c->box; -} - -void childSetMargined(struct child *c, int margined) -{ - setMargined(GTK_CONTAINER(c->box), margined); -} diff --git a/src/libui_sdl/libui/unix/colorbutton.c b/src/libui_sdl/libui/unix/colorbutton.c deleted file mode 100644 index 393b16f..0000000 --- a/src/libui_sdl/libui/unix/colorbutton.c +++ /dev/null @@ -1,80 +0,0 @@ -// 15 may 2016 -#include "uipriv_unix.h" - -struct uiColorButton { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - GtkColorButton *cb; - GtkColorChooser *cc; - void (*onChanged)(uiColorButton *, void *); - void *onChangedData; -}; - -uiUnixControlAllDefaults(uiColorButton) - -static void onColorSet(GtkColorButton *button, gpointer data) -{ - uiColorButton *b = uiColorButton(data); - - (*(b->onChanged))(b, b->onChangedData); -} - -static void defaultOnChanged(uiColorButton *b, void *data) -{ - // do nothing -} - -void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a) -{ - GdkRGBA rgba; - - gtk_color_chooser_get_rgba(b->cc, &rgba); - *r = rgba.red; - *g = rgba.green; - *bl = rgba.blue; - *a = rgba.alpha; -} - -void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a) -{ - GdkRGBA rgba; - - rgba.red = r; - rgba.green = g; - rgba.blue = bl; - rgba.alpha = a; - // no need to inhibit the signal; color-set is documented as only being sent when the user changes the color - gtk_color_chooser_set_rgba(b->cc, &rgba); -} - -void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiColorButton *uiNewColorButton(void) -{ - uiColorButton *b; - GdkRGBA black; - - uiUnixNewControl(uiColorButton, b); - - // I'm not sure what the initial color is; set up a real one - black.red = 0.0; - black.green = 0.0; - black.blue = 0.0; - black.alpha = 1.0; - b->widget = gtk_color_button_new_with_rgba(&black); - b->button = GTK_BUTTON(b->widget); - b->cb = GTK_COLOR_BUTTON(b->widget); - b->cc = GTK_COLOR_CHOOSER(b->widget); - - gtk_color_chooser_set_use_alpha(b->cc, TRUE); - - g_signal_connect(b->widget, "color-set", G_CALLBACK(onColorSet), b); - uiColorButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/src/libui_sdl/libui/unix/combobox.c b/src/libui_sdl/libui/unix/combobox.c deleted file mode 100644 index 6fed804..0000000 --- a/src/libui_sdl/libui/unix/combobox.c +++ /dev/null @@ -1,66 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiCombobox { - uiUnixControl c; - GtkWidget *widget; - GtkComboBox *combobox; - GtkComboBoxText *comboboxText; - void (*onSelected)(uiCombobox *, void *); - void *onSelectedData; - gulong onSelectedSignal; -}; - -uiUnixControlAllDefaults(uiCombobox) - -static void onChanged(GtkComboBox *cbox, gpointer data) -{ - uiCombobox *c = uiCombobox(data); - - (*(c->onSelected))(c, c->onSelectedData); -} - -static void defaultOnSelected(uiCombobox *c, void *data) -{ - // do nothing -} - -void uiComboboxAppend(uiCombobox *c, const char *text) -{ - gtk_combo_box_text_append(c->comboboxText, NULL, text); -} - -int uiComboboxSelected(uiCombobox *c) -{ - return gtk_combo_box_get_active(c->combobox); -} - -void uiComboboxSetSelected(uiCombobox *c, int n) -{ - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(c->combobox, c->onSelectedSignal); - gtk_combo_box_set_active(c->combobox, n); - g_signal_handler_unblock(c->combobox, c->onSelectedSignal); -} - -void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data) -{ - c->onSelected = f; - c->onSelectedData = data; -} - -uiCombobox *uiNewCombobox(void) -{ - uiCombobox *c; - - uiUnixNewControl(uiCombobox, c); - - c->widget = gtk_combo_box_text_new(); - c->combobox = GTK_COMBO_BOX(c->widget); - c->comboboxText = GTK_COMBO_BOX_TEXT(c->widget); - - c->onSelectedSignal = g_signal_connect(c->widget, "changed", G_CALLBACK(onChanged), c); - uiComboboxOnSelected(c, defaultOnSelected, NULL); - - return c; -} diff --git a/src/libui_sdl/libui/unix/control.c b/src/libui_sdl/libui/unix/control.c deleted file mode 100644 index f6fdcea..0000000 --- a/src/libui_sdl/libui/unix/control.c +++ /dev/null @@ -1,14 +0,0 @@ -// 16 august 2015 -#include "uipriv_unix.h" - -void uiUnixControlSetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) -{ - (*(c->SetContainer))(c, container, remove); -} - -#define uiUnixControlSignature 0x556E6978 - -uiUnixControl *uiUnixAllocControl(size_t n, uint32_t typesig, const char *typenamestr) -{ - return uiUnixControl(uiAllocControl(n, uiUnixControlSignature, typesig, typenamestr)); -} diff --git a/src/libui_sdl/libui/unix/datetimepicker.c b/src/libui_sdl/libui/unix/datetimepicker.c deleted file mode 100644 index 19689a2..0000000 --- a/src/libui_sdl/libui/unix/datetimepicker.c +++ /dev/null @@ -1,599 +0,0 @@ -// 4 september 2015 -#include "uipriv_unix.h" - -// LONGTERM imitate gnome-calendar's day/month/year entries above the calendar -// LONGTERM allow entering a 24-hour hour in the hour spinbutton and adjust accordingly - -#define dateTimePickerWidgetType (dateTimePickerWidget_get_type()) -#define dateTimePickerWidget(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), dateTimePickerWidgetType, dateTimePickerWidget)) -#define isDateTimePickerWidget(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), dateTimePickerWidgetType)) -#define dateTimePickerWidgetClass(class) (G_TYPE_CHECK_CLASS_CAST((class), dateTimePickerWidgetType, dateTimePickerWidgetClass)) -#define isDateTimePickerWidgetClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), dateTimePickerWidget)) -#define getDateTimePickerWidgetClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), dateTimePickerWidgetType, dateTimePickerWidgetClass)) - -typedef struct dateTimePickerWidget dateTimePickerWidget; -typedef struct dateTimePickerWidgetClass dateTimePickerWidgetClass; - -struct dateTimePickerWidget { - GtkToggleButton parent_instance; - - gulong toggledSignal; - - gboolean hasTime; - gboolean hasDate; - - GtkWidget *window; - GtkWidget *box; - GtkWidget *calendar; - GtkWidget *timebox; - GtkWidget *hours; - GtkWidget *minutes; - GtkWidget *seconds; - GtkWidget *ampm; - - gulong hoursBlock; - gulong minutesBlock; - gulong secondsBlock; - gulong ampmBlock; - - GdkDevice *keyboard; - GdkDevice *mouse; -}; - -struct dateTimePickerWidgetClass { - GtkToggleButtonClass parent_class; -}; - -G_DEFINE_TYPE(dateTimePickerWidget, dateTimePickerWidget, GTK_TYPE_TOGGLE_BUTTON) - -static int realSpinValue(GtkSpinButton *spinButton) -{ - GtkAdjustment *adj; - - adj = gtk_spin_button_get_adjustment(spinButton); - return (int) gtk_adjustment_get_value(adj); -} - -static void setRealSpinValue(GtkSpinButton *spinButton, int value, gulong block) -{ - GtkAdjustment *adj; - - g_signal_handler_block(spinButton, block); - adj = gtk_spin_button_get_adjustment(spinButton); - gtk_adjustment_set_value(adj, value); - g_signal_handler_unblock(spinButton, block); -} - -static GDateTime *selected(dateTimePickerWidget *d) -{ - // choose a day for which all times are likely to be valid for the default date in case we're only dealing with time - guint year = 1970, month = 1, day = 1; - guint hour = 0, minute = 0, second = 0; - - if (d->hasDate) { - gtk_calendar_get_date(GTK_CALENDAR(d->calendar), &year, &month, &day); - month++; // GtkCalendar/GDateTime differences - } - if (d->hasTime) { - hour = realSpinValue(GTK_SPIN_BUTTON(d->hours)); - if (realSpinValue(GTK_SPIN_BUTTON(d->ampm)) != 0) - hour += 12; - minute = realSpinValue(GTK_SPIN_BUTTON(d->minutes)); - second = realSpinValue(GTK_SPIN_BUTTON(d->seconds)); - } - return g_date_time_new_local(year, month, day, hour, minute, second); -} - -static void setLabel(dateTimePickerWidget *d) -{ - GDateTime *dt; - char *fmt; - char *msg; - gboolean free; - - dt = selected(d); - free = FALSE; - if (d->hasDate && d->hasTime) { - // don't use D_T_FMT; that's too verbose - fmt = g_strdup_printf("%s %s", nl_langinfo(D_FMT), nl_langinfo(T_FMT)); - free = TRUE; - } else if (d->hasDate) - fmt = nl_langinfo(D_FMT); - else - fmt = nl_langinfo(T_FMT); - msg = g_date_time_format(dt, fmt); - gtk_button_set_label(GTK_BUTTON(d), msg); - g_free(msg); - if (free) - g_free(fmt); - g_date_time_unref(dt); -} - -static void dateTimeChanged(dateTimePickerWidget *d) -{ - setLabel(d); - // TODO fire event here -} - -// we don't want ::toggled to be sent again -static void setActive(dateTimePickerWidget *d, gboolean active) -{ - g_signal_handler_block(d, d->toggledSignal); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d), active); - g_signal_handler_unblock(d, d->toggledSignal); -} - -// like startGrab() below, a lot of this is in the order that GtkComboBox does it -static void endGrab(dateTimePickerWidget *d) -{ - if (d->keyboard != NULL) - gdk_device_ungrab(d->keyboard, GDK_CURRENT_TIME); - gdk_device_ungrab(d->mouse, GDK_CURRENT_TIME); - gtk_device_grab_remove(d->window, d->mouse); - d->keyboard = NULL; - d->mouse = NULL; -} - -static void hidePopup(dateTimePickerWidget *d) -{ - endGrab(d); - gtk_widget_hide(d->window); - setActive(d, FALSE); -} - -// this consolidates a good chunk of what GtkComboBox does -static gboolean startGrab(dateTimePickerWidget *d) -{ - GdkDevice *dev; - guint32 time; - GdkWindow *window; - GdkDevice *keyboard, *mouse; - - dev = gtk_get_current_event_device(); - if (dev == NULL) { - // this is what GtkComboBox does - // since no device was set, just use the first available "master device" - GdkDisplay *disp; - GdkDeviceManager *dm; - GList *list; - - disp = gtk_widget_get_display(GTK_WIDGET(d)); - dm = gdk_display_get_device_manager(disp); - list = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_MASTER); - dev = (GdkDevice *) (list->data); - g_list_free(list); - } - - time = gtk_get_current_event_time(); - keyboard = dev; - mouse = gdk_device_get_associated_device(dev); - if (gdk_device_get_source(dev) != GDK_SOURCE_KEYBOARD) { - dev = mouse; - mouse = keyboard; - keyboard = dev; - } - - window = gtk_widget_get_window(d->window); - if (keyboard != NULL) - if (gdk_device_grab(keyboard, window, - GDK_OWNERSHIP_WINDOW, TRUE, - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, - NULL, time) != GDK_GRAB_SUCCESS) - return FALSE; - if (mouse != NULL) - if (gdk_device_grab(mouse, window, - GDK_OWNERSHIP_WINDOW, TRUE, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK, - NULL, time) != GDK_GRAB_SUCCESS) { - if (keyboard != NULL) - gdk_device_ungrab(keyboard, time); - return FALSE; - } - - gtk_device_grab_add(d->window, mouse, TRUE); - d->keyboard = keyboard; - d->mouse = mouse; - return TRUE; -} - -// based on gtk_combo_box_list_position() in the GTK+ source code -static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y) -{ - GdkWindow *window; - GtkAllocation a; - GtkRequisition aWin; - GdkScreen *screen; - GdkRectangle workarea; - int otherY; - - gtk_widget_get_allocation(GTK_WIDGET(d), &a); - gtk_widget_get_preferred_size(d->window, &aWin, NULL); - *x = 0; - *y = 0; - if (!gtk_widget_get_has_window(GTK_WIDGET(d))) { - *x = a.x; - *y = a.y; - } - window = gtk_widget_get_window(GTK_WIDGET(d)); - gdk_window_get_root_coords(window, *x, *y, x, y); - if (gtk_widget_get_direction(GTK_WIDGET(d)) == GTK_TEXT_DIR_RTL) - *x += a.width - aWin.width; - - // now adjust to prevent the box from going offscreen - screen = gtk_widget_get_screen(GTK_WIDGET(d)); - gdk_screen_get_monitor_workarea(screen, - gdk_screen_get_monitor_at_window(screen, window), - &workarea); - if (*x < workarea.x) // too far to the left? - *x = workarea.x; - else if (*x + aWin.width > (workarea.x + workarea.width)) // too far to the right? - *x = (workarea.x + workarea.width) - aWin.width; - // this isn't the same algorithm used by GtkComboBox - // first, get our two choices; *y for down and otherY for up - otherY = *y - aWin.height; - *y += a.height; - // and use otherY if we're too low - if (*y + aWin.height >= workarea.y + workarea.height) - *y = otherY; -} - -static void showPopup(dateTimePickerWidget *d) -{ - GtkWidget *toplevel; - gint x, y; - - // GtkComboBox does it - toplevel = gtk_widget_get_toplevel(GTK_WIDGET(d)); - if (GTK_IS_WINDOW(toplevel)) - gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(toplevel)), GTK_WINDOW(d->window)); - - allocationToScreen(d, &x, &y); - gtk_window_move(GTK_WINDOW(d->window), x, y); - - gtk_widget_show(d->window); - setActive(d, TRUE); - - if (!startGrab(d)) - hidePopup(d); -} - -static void onToggled(GtkToggleButton *b, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(b); - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d))) - showPopup(d); - else - hidePopup(d); -} - -static gboolean grabBroken(GtkWidget *w, GdkEventGrabBroken *e, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - - hidePopup(d); - return TRUE; // this is what GtkComboBox does -} - -static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - int winx, winy; - GtkAllocation wina; - gboolean in; - - gtk_widget_get_allocation(d->window, &wina); - winx = 0; - winy = 0; - if (!gtk_widget_get_has_window(d->window)) { - winx = wina.x; - winy = wina.y; - } - gdk_window_get_root_coords(gtk_widget_get_window(d->window), winx, winy, &winx, &winy); - in = TRUE; - if (e->x_root < winx) - in = FALSE; - if (e->x_root >= (winx + wina.width)) - in = FALSE; - if (e->y_root < winy) - in = FALSE; - if (e->y_root >= (winy + wina.height)) - in = FALSE; - if (!in) - hidePopup(d); - return TRUE; // this is what GtkComboBox does -} - -static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) -{ - double *out = (double *) ptr; - const gchar *text; - int value; - - text = gtk_entry_get_text(GTK_ENTRY(sb)); - value = (int) g_strtod(text, NULL); - if (value < 0 || value > 12) - return GTK_INPUT_ERROR; - if (value == 12) // 12 to the user is 0 internally - value = 0; - *out = (double) value; - return TRUE; -} - -static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data) -{ - gchar *text; - int value; - - value = realSpinValue(sb); - if (value == 0) // 0 internally is 12 to the user - value = 12; - text = g_strdup_printf("%d", value); - gtk_entry_set_text(GTK_ENTRY(sb), text); - g_free(text); - return TRUE; -} - -static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data) -{ - gchar *text; - int value; - - value = realSpinValue(sb); - text = g_strdup_printf("%02d", value); - gtk_entry_set_text(GTK_ENTRY(sb), text); - g_free(text); - return TRUE; -} - -// this is really hacky but we can't use GtkCombobox here :( -static gint ampmSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) -{ - double *out = (double *) ptr; - const gchar *text; - char firstAM, firstPM; - - text = gtk_entry_get_text(GTK_ENTRY(sb)); - // LONGTERM don't use ASCII here for case insensitivity - firstAM = g_ascii_tolower(nl_langinfo(AM_STR)[0]); - firstPM = g_ascii_tolower(nl_langinfo(PM_STR)[0]); - for (; *text != '\0'; text++) - if (g_ascii_tolower(*text) == firstAM) { - *out = 0; - return TRUE; - } else if (g_ascii_tolower(*text) == firstPM) { - *out = 1; - return TRUE; - } - return GTK_INPUT_ERROR; -} - -static gboolean ampmSpinboxOutput(GtkSpinButton *sb, gpointer data) -{ - int value; - - value = gtk_spin_button_get_value_as_int(sb); - if (value == 0) - gtk_entry_set_text(GTK_ENTRY(sb), nl_langinfo(AM_STR)); - else - gtk_entry_set_text(GTK_ENTRY(sb), nl_langinfo(PM_STR)); - return TRUE; -} - -static void spinboxChanged(GtkSpinButton *sb, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - - dateTimeChanged(d); -} - -static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, gint (*input)(GtkSpinButton *, gpointer, gpointer), gboolean (*output)(GtkSpinButton *, gpointer), gulong *block) -{ - GtkWidget *sb; - - sb = gtk_spin_button_new_with_range(min, max, 1); - gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sb), TRUE); - gtk_orientable_set_orientation(GTK_ORIENTABLE(sb), GTK_ORIENTATION_VERTICAL); - *block = g_signal_connect(sb, "value-changed", G_CALLBACK(spinboxChanged), d); - if (input != NULL) - g_signal_connect(sb, "input", G_CALLBACK(input), NULL); - if (output != NULL) - g_signal_connect(sb, "output", G_CALLBACK(output), NULL); - return sb; -} - -static void dateChanged(GtkCalendar *c, gpointer data) -{ - dateTimePickerWidget *d = dateTimePickerWidget(data); - - dateTimeChanged(d); -} - -static void setDateOnly(dateTimePickerWidget *d) -{ - d->hasTime = FALSE; - gtk_container_remove(GTK_CONTAINER(d->box), d->timebox); -} - -static void setTimeOnly(dateTimePickerWidget *d) -{ - d->hasDate = FALSE; - gtk_container_remove(GTK_CONTAINER(d->box), d->calendar); -} - -static void dateTimePickerWidget_init(dateTimePickerWidget *d) -{ - GDateTime *dt; - gint year, month, day; - gint hour; - gulong calendarBlock; - - d->window = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_resizable(GTK_WINDOW(d->window), FALSE); - gtk_window_set_attached_to(GTK_WINDOW(d->window), GTK_WIDGET(d)); - gtk_window_set_decorated(GTK_WINDOW(d->window), FALSE); - gtk_window_set_deletable(GTK_WINDOW(d->window), FALSE); - gtk_window_set_type_hint(GTK_WINDOW(d->window), GDK_WINDOW_TYPE_HINT_COMBO); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(d->window), TRUE); - gtk_window_set_skip_pager_hint(GTK_WINDOW(d->window), TRUE); - gtk_window_set_has_resize_grip(GTK_WINDOW(d->window), FALSE); - gtk_container_set_border_width(GTK_CONTAINER(d->window), 12); - // and make it stand out a bit - gtk_style_context_add_class(gtk_widget_get_style_context(d->window), "frame"); - - d->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_container_add(GTK_CONTAINER(d->window), d->box); - - d->calendar = gtk_calendar_new(); - calendarBlock = g_signal_connect(d->calendar, "day-selected", G_CALLBACK(dateChanged), d); - gtk_container_add(GTK_CONTAINER(d->box), d->calendar); - - d->timebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_widget_set_valign(d->timebox, GTK_ALIGN_CENTER); - gtk_container_add(GTK_CONTAINER(d->box), d->timebox); - - d->hours = newSpinbox(d, 0, 11, hoursSpinboxInput, hoursSpinboxOutput, &(d->hoursBlock)); - gtk_container_add(GTK_CONTAINER(d->timebox), d->hours); - - gtk_container_add(GTK_CONTAINER(d->timebox), - gtk_label_new(":")); - - d->minutes = newSpinbox(d, 0, 59, NULL, zeroPadSpinbox, &(d->minutesBlock)); - gtk_container_add(GTK_CONTAINER(d->timebox), d->minutes); - - gtk_container_add(GTK_CONTAINER(d->timebox), - gtk_label_new(":")); - - d->seconds = newSpinbox(d, 0, 59, NULL, zeroPadSpinbox, &(d->secondsBlock)); - gtk_container_add(GTK_CONTAINER(d->timebox), d->seconds); - - // LONGTERM this should be the case, but that interferes with grabs - // switch to it when we can drop GTK+ 3.10 and use popovers -#if 0 - d->ampm = gtk_combo_box_text_new(); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(d->ampm), NULL, "AM"); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(d->ampm), NULL, "PM"); -#endif - d->ampm = newSpinbox(d, 0, 1, ampmSpinboxInput, ampmSpinboxOutput, &(d->ampmBlock)); - gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(d->ampm), FALSE); - gtk_widget_set_valign(d->ampm, GTK_ALIGN_CENTER); - gtk_container_add(GTK_CONTAINER(d->timebox), d->ampm); - - gtk_widget_show_all(d->box); - - g_signal_connect(d->window, "grab-broken-event", G_CALLBACK(grabBroken), d); - g_signal_connect(d->window, "button-release-event", G_CALLBACK(buttonReleased), d); - - d->toggledSignal = g_signal_connect(d, "toggled", G_CALLBACK(onToggled), NULL); - d->keyboard = NULL; - d->mouse = NULL; - - d->hasTime = TRUE; - d->hasDate = TRUE; - - // set the current date/time - // notice how we block signals from firing - dt = g_date_time_new_now_local(); - g_date_time_get_ymd(dt, &year, &month, &day); - month--; // GDateTime/GtkCalendar differences - g_signal_handler_block(d->calendar, calendarBlock); - gtk_calendar_select_month(GTK_CALENDAR(d->calendar), month, year); - gtk_calendar_select_day(GTK_CALENDAR(d->calendar), day); - g_signal_handler_unblock(d->calendar, calendarBlock); - hour = g_date_time_get_hour(dt); - if (hour >= 12) { - hour -= 12; - setRealSpinValue(GTK_SPIN_BUTTON(d->ampm), 1, d->ampmBlock); - } - setRealSpinValue(GTK_SPIN_BUTTON(d->hours), hour, d->hoursBlock); - setRealSpinValue(GTK_SPIN_BUTTON(d->minutes), g_date_time_get_minute(dt), d->minutesBlock); - setRealSpinValue(GTK_SPIN_BUTTON(d->seconds), g_date_time_get_seconds(dt), d->secondsBlock); - g_date_time_unref(dt); -} - -static void dateTimePickerWidget_dispose(GObject *obj) -{ - dateTimePickerWidget *d = dateTimePickerWidget(obj); - - if (d->window != NULL) { - gtk_widget_destroy(d->window); - d->window = NULL; - } - G_OBJECT_CLASS(dateTimePickerWidget_parent_class)->dispose(obj); -} - -static void dateTimePickerWidget_finalize(GObject *obj) -{ - G_OBJECT_CLASS(dateTimePickerWidget_parent_class)->finalize(obj); -} - -static void dateTimePickerWidget_class_init(dateTimePickerWidgetClass *class) -{ - G_OBJECT_CLASS(class)->dispose = dateTimePickerWidget_dispose; - G_OBJECT_CLASS(class)->finalize = dateTimePickerWidget_finalize; -} - -static GtkWidget *newDTP(void) -{ - GtkWidget *w; - - w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); - setLabel(dateTimePickerWidget(w)); - return w; -} - -static GtkWidget *newDP(void) -{ - GtkWidget *w; - - w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); - setDateOnly(dateTimePickerWidget(w)); - setLabel(dateTimePickerWidget(w)); - return w; -} - -static GtkWidget *newTP(void) -{ - GtkWidget *w; - - w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); - setTimeOnly(dateTimePickerWidget(w)); - setLabel(dateTimePickerWidget(w)); - return w; -} - -struct uiDateTimePicker { - uiUnixControl c; - GtkWidget *widget; - dateTimePickerWidget *d; -}; - -uiUnixControlAllDefaults(uiDateTimePicker) - -uiDateTimePicker *finishNewDateTimePicker(GtkWidget *(*fn)(void)) -{ - uiDateTimePicker *d; - - uiUnixNewControl(uiDateTimePicker, d); - - d->widget = (*fn)(); - d->d = dateTimePickerWidget(d->widget); - - return d; -} - -uiDateTimePicker *uiNewDateTimePicker(void) -{ - return finishNewDateTimePicker(newDTP); -} - -uiDateTimePicker *uiNewDatePicker(void) -{ - return finishNewDateTimePicker(newDP); -} - -uiDateTimePicker *uiNewTimePicker(void) -{ - return finishNewDateTimePicker(newTP); -} diff --git a/src/libui_sdl/libui/unix/debug.c b/src/libui_sdl/libui/unix/debug.c deleted file mode 100644 index c948db6..0000000 --- a/src/libui_sdl/libui/unix/debug.c +++ /dev/null @@ -1,14 +0,0 @@ -// 13 may 2016 -#include "uipriv_unix.h" - -// LONGTERM don't halt on release builds - -void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap) -{ - char *a, *b; - - a = g_strdup_printf("[libui] %s:%s:%s() %s", file, line, func, prefix); - b = g_strdup_vprintf(format, ap); - g_critical("%s%s", a, b); - G_BREAKPOINT(); -} diff --git a/src/libui_sdl/libui/unix/draw.c b/src/libui_sdl/libui/unix/draw.c deleted file mode 100644 index 5befcd3..0000000 --- a/src/libui_sdl/libui/unix/draw.c +++ /dev/null @@ -1,214 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -uiDrawContext *newContext(cairo_t *cr) -{ - uiDrawContext *c; - - c = uiNew(uiDrawContext); - c->cr = cr; - return c; -} - -void freeContext(uiDrawContext *c) -{ - uiFree(c); -} - -static cairo_pattern_t *mkbrush(uiDrawBrush *b) -{ - cairo_pattern_t *pat; - size_t i; - - switch (b->Type) { - case uiDrawBrushTypeSolid: - pat = cairo_pattern_create_rgba(b->R, b->G, b->B, b->A); - break; - case uiDrawBrushTypeLinearGradient: - pat = cairo_pattern_create_linear(b->X0, b->Y0, b->X1, b->Y1); - break; - case uiDrawBrushTypeRadialGradient: - // make the start circle radius 0 to make it a point - pat = cairo_pattern_create_radial( - b->X0, b->Y0, 0, - b->X1, b->Y1, b->OuterRadius); - break; -// case uiDrawBrushTypeImage: - } - if (cairo_pattern_status(pat) != CAIRO_STATUS_SUCCESS) - implbug("error creating pattern in mkbrush(): %s", - cairo_status_to_string(cairo_pattern_status(pat))); - switch (b->Type) { - case uiDrawBrushTypeLinearGradient: - case uiDrawBrushTypeRadialGradient: - for (i = 0; i < b->NumStops; i++) - cairo_pattern_add_color_stop_rgba(pat, - b->Stops[i].Pos, - b->Stops[i].R, - b->Stops[i].G, - b->Stops[i].B, - b->Stops[i].A); - } - return pat; -} - -void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p) -{ - cairo_pattern_t *pat; - - runPath(path, c->cr); - pat = mkbrush(b); - cairo_set_source(c->cr, pat); - switch (p->Cap) { - case uiDrawLineCapFlat: - cairo_set_line_cap(c->cr, CAIRO_LINE_CAP_BUTT); - break; - case uiDrawLineCapRound: - cairo_set_line_cap(c->cr, CAIRO_LINE_CAP_ROUND); - break; - case uiDrawLineCapSquare: - cairo_set_line_cap(c->cr, CAIRO_LINE_CAP_SQUARE); - break; - } - switch (p->Join) { - case uiDrawLineJoinMiter: - cairo_set_line_join(c->cr, CAIRO_LINE_JOIN_MITER); - cairo_set_miter_limit(c->cr, p->MiterLimit); - break; - case uiDrawLineJoinRound: - cairo_set_line_join(c->cr, CAIRO_LINE_JOIN_ROUND); - break; - case uiDrawLineJoinBevel: - cairo_set_line_join(c->cr, CAIRO_LINE_JOIN_BEVEL); - break; - } - cairo_set_line_width(c->cr, p->Thickness); - cairo_set_dash(c->cr, p->Dashes, p->NumDashes, p->DashPhase); - cairo_stroke(c->cr); - cairo_pattern_destroy(pat); -} - -void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b) -{ - cairo_pattern_t *pat; - - runPath(path, c->cr); - pat = mkbrush(b); - cairo_set_source(c->cr, pat); - switch (pathFillMode(path)) { - case uiDrawFillModeWinding: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_WINDING); - break; - case uiDrawFillModeAlternate: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_EVEN_ODD); - break; - } - cairo_fill(c->cr); - cairo_pattern_destroy(pat); -} - -void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m) -{ - cairo_matrix_t cm; - - m2c(m, &cm); - cairo_transform(c->cr, &cm); -} - -void uiDrawClip(uiDrawContext *c, uiDrawPath *path) -{ - runPath(path, c->cr); - switch (pathFillMode(path)) { - case uiDrawFillModeWinding: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_WINDING); - break; - case uiDrawFillModeAlternate: - cairo_set_fill_rule(c->cr, CAIRO_FILL_RULE_EVEN_ODD); - break; - } - cairo_clip(c->cr); -} - -void uiDrawSave(uiDrawContext *c) -{ - cairo_save(c->cr); -} - -void uiDrawRestore(uiDrawContext *c) -{ - cairo_restore(c->cr); -} - - -// bitmap API - -uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha) -{ - uiDrawBitmap* bmp; - - bmp = uiNew(uiDrawBitmap); - - bmp->bmp = cairo_image_surface_create(alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height); - if (cairo_surface_status(bmp->bmp) != CAIRO_STATUS_SUCCESS) - implbug("error creating bitmap: %s", - cairo_status_to_string(cairo_surface_status(bmp->bmp))); - - bmp->Width = width; - bmp->Height = height; - bmp->Stride = cairo_image_surface_get_stride(bmp->bmp); - - return bmp; -} - -void uiDrawBitmapUpdate(uiDrawBitmap* bmp, const void* data) -{ - const unsigned char* src = data; - unsigned char* dst = cairo_image_surface_get_data(bmp->bmp); - - if (bmp->Stride == bmp->Width*4) - { - // stride 'good', can just directly copy all the shit - memcpy(dst, src, bmp->Stride*bmp->Height); - } - else - { - int y; - for (y = 0; y < bmp->Height; y++) - { - memcpy(dst, src, bmp->Width*4); - src += bmp->Width*4; - dst += bmp->Stride; - } - } - - cairo_surface_mark_dirty(bmp->bmp); -} - -void uiDrawBitmapDraw(uiDrawContext* c, uiDrawBitmap* bmp, uiRect* srcrect, uiRect* dstrect, int filter) -{ - cairo_save(c->cr); - cairo_rectangle(c->cr, dstrect->X, dstrect->Y, dstrect->Width, dstrect->Height); - - cairo_translate(c->cr, dstrect->X, dstrect->Y); - if ((dstrect->Width != srcrect->Width) || (dstrect->Height != srcrect->Height)) - { - // scale shit if needed - double sx = dstrect->Width / (double)srcrect->Width; - double sy = dstrect->Height / (double)srcrect->Height; - cairo_scale(c->cr, sx, sy); - } - - cairo_set_source_surface(c->cr, bmp->bmp, -srcrect->X, -srcrect->Y); - cairo_pattern_set_filter(cairo_get_source(c->cr), filter ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_NEAREST); - cairo_clip(c->cr); - cairo_paint(c->cr); - - cairo_restore(c->cr); -} - -void uiDrawFreeBitmap(uiDrawBitmap* bmp) -{ - cairo_surface_destroy(bmp->bmp); - uiFree(bmp); -} diff --git a/src/libui_sdl/libui/unix/draw.h b/src/libui_sdl/libui/unix/draw.h deleted file mode 100644 index 869acd1..0000000 --- a/src/libui_sdl/libui/unix/draw.h +++ /dev/null @@ -1,21 +0,0 @@ -// 5 may 2016 - -// draw.c -struct uiDrawContext { - cairo_t *cr; -}; - -struct uiDrawBitmap { - int Width; - int Height; - int Stride; - - cairo_surface_t* bmp; -}; - -// drawpath.c -extern void runPath(uiDrawPath *p, cairo_t *cr); -extern uiDrawFillMode pathFillMode(uiDrawPath *path); - -// drawmatrix.c -extern void m2c(uiDrawMatrix *m, cairo_matrix_t *c); diff --git a/src/libui_sdl/libui/unix/drawmatrix.c b/src/libui_sdl/libui/unix/drawmatrix.c deleted file mode 100644 index f12b303..0000000 --- a/src/libui_sdl/libui/unix/drawmatrix.c +++ /dev/null @@ -1,115 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -void m2c(uiDrawMatrix *m, cairo_matrix_t *c) -{ - c->xx = m->M11; - c->yx = m->M12; - c->xy = m->M21; - c->yy = m->M22; - c->x0 = m->M31; - c->y0 = m->M32; -} - -static void c2m(cairo_matrix_t *c, uiDrawMatrix *m) -{ - m->M11 = c->xx; - m->M12 = c->yx; - m->M21 = c->xy; - m->M22 = c->yy; - m->M31 = c->x0; - m->M32 = c->y0; -} - -void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y) -{ - cairo_matrix_t c; - cairo_matrix_t tmp; - - m2c(m, &c); - cairo_matrix_init_translate(&tmp, x, y); - cairo_matrix_multiply(&c, &c, &tmp); - c2m(&c, m); -} - -void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y) -{ - cairo_matrix_t c; - cairo_matrix_t tmp; - double xt, yt; - - m2c(m, &c); - xt = x; - yt = y; - scaleCenter(xCenter, yCenter, &xt, &yt); - cairo_matrix_init_translate(&tmp, xt, yt); - cairo_matrix_scale(&tmp, x, y); - cairo_matrix_translate(&tmp, -xt, -yt); - cairo_matrix_multiply(&c, &c, &tmp); - c2m(&c, m); -} - -void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount) -{ - cairo_matrix_t c; - cairo_matrix_t tmp; - - m2c(m, &c); - cairo_matrix_init_translate(&tmp, x, y); - cairo_matrix_rotate(&tmp, amount); - cairo_matrix_translate(&tmp, -x, -y); - cairo_matrix_multiply(&c, &c, &tmp); - c2m(&c, m); -} - -void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) -{ - fallbackSkew(m, x, y, xamount, yamount); -} - -void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src) -{ - cairo_matrix_t c; - cairo_matrix_t d; - - m2c(dest, &c); - m2c(src, &d); - cairo_matrix_multiply(&c, &c, &d); - c2m(&c, dest); -} - -int uiDrawMatrixInvertible(uiDrawMatrix *m) -{ - cairo_matrix_t c; - - m2c(m, &c); - return cairo_matrix_invert(&c) == CAIRO_STATUS_SUCCESS; -} - -int uiDrawMatrixInvert(uiDrawMatrix *m) -{ - cairo_matrix_t c; - - m2c(m, &c); - if (cairo_matrix_invert(&c) != CAIRO_STATUS_SUCCESS) - return 0; - c2m(&c, m); - return 1; -} - -void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y) -{ - cairo_matrix_t c; - - m2c(m, &c); - cairo_matrix_transform_point(&c, x, y); -} - -void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y) -{ - cairo_matrix_t c; - - m2c(m, &c); - cairo_matrix_transform_distance(&c, x, y); -} diff --git a/src/libui_sdl/libui/unix/drawpath.c b/src/libui_sdl/libui/unix/drawpath.c deleted file mode 100644 index a0165fb..0000000 --- a/src/libui_sdl/libui/unix/drawpath.c +++ /dev/null @@ -1,199 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -struct uiDrawPath { - GArray *pieces; - uiDrawFillMode fillMode; - gboolean ended; -}; - -struct piece { - int type; - double d[8]; - int b; -}; - -enum { - newFigure, - newFigureArc, - lineTo, - arcTo, - bezierTo, - closeFigure, - addRect, -}; - -uiDrawPath *uiDrawNewPath(uiDrawFillMode mode) -{ - uiDrawPath *p; - - p = uiNew(uiDrawPath); - p->pieces = g_array_new(FALSE, TRUE, sizeof (struct piece)); - p->fillMode = mode; - return p; -} - -void uiDrawFreePath(uiDrawPath *p) -{ - g_array_free(p->pieces, TRUE); - uiFree(p); -} - -static void add(uiDrawPath *p, struct piece *piece) -{ - if (p->ended) - userbug("You cannot modify a uiDrawPath that has been ended. (path: %p)", p); - g_array_append_vals(p->pieces, piece, 1); -} - -void uiDrawPathNewFigure(uiDrawPath *p, double x, double y) -{ - struct piece piece; - - piece.type = newFigure; - piece.d[0] = x; - piece.d[1] = y; - add(p, &piece); -} - -void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - struct piece piece; - - if (sweep > 2 * uiPi) - sweep = 2 * uiPi; - piece.type = newFigureArc; - piece.d[0] = xCenter; - piece.d[1] = yCenter; - piece.d[2] = radius; - piece.d[3] = startAngle; - piece.d[4] = sweep; - piece.b = negative; - add(p, &piece); -} - -void uiDrawPathLineTo(uiDrawPath *p, double x, double y) -{ - struct piece piece; - - piece.type = lineTo; - piece.d[0] = x; - piece.d[1] = y; - add(p, &piece); -} - -void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - struct piece piece; - - if (sweep > 2 * uiPi) - sweep = 2 * uiPi; - piece.type = arcTo; - piece.d[0] = xCenter; - piece.d[1] = yCenter; - piece.d[2] = radius; - piece.d[3] = startAngle; - piece.d[4] = sweep; - piece.b = negative; - add(p, &piece); -} - -void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY) -{ - struct piece piece; - - piece.type = bezierTo; - piece.d[0] = c1x; - piece.d[1] = c1y; - piece.d[2] = c2x; - piece.d[3] = c2y; - piece.d[4] = endX; - piece.d[5] = endY; - add(p, &piece); -} - -void uiDrawPathCloseFigure(uiDrawPath *p) -{ - struct piece piece; - - piece.type = closeFigure; - add(p, &piece); -} - -void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height) -{ - struct piece piece; - - piece.type = addRect; - piece.d[0] = x; - piece.d[1] = y; - piece.d[2] = width; - piece.d[3] = height; - add(p, &piece); -} - -void uiDrawPathEnd(uiDrawPath *p) -{ - p->ended = TRUE; -} - -void runPath(uiDrawPath *p, cairo_t *cr) -{ - guint i; - struct piece *piece; - void (*arc)(cairo_t *, double, double, double, double, double); - - if (!p->ended) - userbug("You cannot draw with a uiDrawPath that has not been ended. (path: %p)", p); - cairo_new_path(cr); - for (i = 0; i < p->pieces->len; i++) { - piece = &g_array_index(p->pieces, struct piece, i); - switch (piece->type) { - case newFigure: - cairo_move_to(cr, piece->d[0], piece->d[1]); - break; - case newFigureArc: - cairo_new_sub_path(cr); - // fall through - case arcTo: - arc = cairo_arc; - if (piece->b) - arc = cairo_arc_negative; - (*arc)(cr, - piece->d[0], - piece->d[1], - piece->d[2], - piece->d[3], - piece->d[3] + piece->d[4]); - break; - case lineTo: - cairo_line_to(cr, piece->d[0], piece->d[1]); - break; - case bezierTo: - cairo_curve_to(cr, - piece->d[0], - piece->d[1], - piece->d[2], - piece->d[3], - piece->d[4], - piece->d[5]); - break; - case closeFigure: - cairo_close_path(cr); - break; - case addRect: - cairo_rectangle(cr, - piece->d[0], - piece->d[1], - piece->d[2], - piece->d[3]); - break; - } - } -} - -uiDrawFillMode pathFillMode(uiDrawPath *path) -{ - return path->fillMode; -} diff --git a/src/libui_sdl/libui/unix/drawtext.c b/src/libui_sdl/libui/unix/drawtext.c deleted file mode 100644 index 7078e1a..0000000 --- a/src/libui_sdl/libui/unix/drawtext.c +++ /dev/null @@ -1,293 +0,0 @@ -// 6 september 2015 -#include "uipriv_unix.h" -#include "draw.h" - -struct uiDrawFontFamilies { - PangoFontFamily **f; - int n; -}; - -uiDrawFontFamilies *uiDrawListFontFamilies(void) -{ - uiDrawFontFamilies *ff; - PangoFontMap *map; - - ff = uiNew(uiDrawFontFamilies); - map = pango_cairo_font_map_get_default(); - pango_font_map_list_families(map, &(ff->f), &(ff->n)); - // do not free map; it's a shared resource - return ff; -} - -int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff) -{ - return ff->n; -} - -char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n) -{ - PangoFontFamily *f; - - f = ff->f[n]; - return uiUnixStrdupText(pango_font_family_get_name(f)); -} - -void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) -{ - g_free(ff->f); - uiFree(ff); -} - -struct uiDrawTextFont { - PangoFont *f; -}; - -uiDrawTextFont *mkTextFont(PangoFont *f, gboolean ref) -{ - uiDrawTextFont *font; - - font = uiNew(uiDrawTextFont); - font->f = f; - if (ref) - g_object_ref(font->f); - return font; -} - -static const PangoWeight pangoWeights[] = { - [uiDrawTextWeightThin] = PANGO_WEIGHT_THIN, - [uiDrawTextWeightUltraLight] = PANGO_WEIGHT_ULTRALIGHT, - [uiDrawTextWeightLight] = PANGO_WEIGHT_LIGHT, - [uiDrawTextWeightBook] = PANGO_WEIGHT_BOOK, - [uiDrawTextWeightNormal] = PANGO_WEIGHT_NORMAL, - [uiDrawTextWeightMedium] = PANGO_WEIGHT_MEDIUM, - [uiDrawTextWeightSemiBold] = PANGO_WEIGHT_SEMIBOLD, - [uiDrawTextWeightBold] = PANGO_WEIGHT_BOLD, - [uiDrawTextWeightUltraBold] = PANGO_WEIGHT_ULTRABOLD, - [uiDrawTextWeightHeavy] = PANGO_WEIGHT_HEAVY, - [uiDrawTextWeightUltraHeavy] = PANGO_WEIGHT_ULTRAHEAVY, -}; - -static const PangoStyle pangoItalics[] = { - [uiDrawTextItalicNormal] = PANGO_STYLE_NORMAL, - [uiDrawTextItalicOblique] = PANGO_STYLE_OBLIQUE, - [uiDrawTextItalicItalic] = PANGO_STYLE_ITALIC, -}; - -static const PangoStretch pangoStretches[] = { - [uiDrawTextStretchUltraCondensed] = PANGO_STRETCH_ULTRA_CONDENSED, - [uiDrawTextStretchExtraCondensed] = PANGO_STRETCH_EXTRA_CONDENSED, - [uiDrawTextStretchCondensed] = PANGO_STRETCH_CONDENSED, - [uiDrawTextStretchSemiCondensed] = PANGO_STRETCH_SEMI_CONDENSED, - [uiDrawTextStretchNormal] = PANGO_STRETCH_NORMAL, - [uiDrawTextStretchSemiExpanded] = PANGO_STRETCH_SEMI_EXPANDED, - [uiDrawTextStretchExpanded] = PANGO_STRETCH_EXPANDED, - [uiDrawTextStretchExtraExpanded] = PANGO_STRETCH_EXTRA_EXPANDED, - [uiDrawTextStretchUltraExpanded] = PANGO_STRETCH_ULTRA_EXPANDED, -}; - -// we need a context for a few things -// the documentation suggests creating cairo_t-specific, GdkScreen-specific, or even GtkWidget-specific contexts, but we can't really do that because we want our uiDrawTextFonts and uiDrawTextLayouts to be context-independent -// we could use pango_font_map_create_context(pango_cairo_font_map_get_default()) but that will ignore GDK-specific settings -// so let's use gdk_pango_context_get() instead; even though it's for the default screen only, it's good enough for us -#define mkGenericPangoCairoContext() (gdk_pango_context_get()) - -PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc) -{ - PangoFont *f; - PangoContext *context; - - // in this case, the context is necessary for the metrics to be correct - context = mkGenericPangoCairoContext(); - f = pango_font_map_load_font(pango_cairo_font_map_get_default(), context, pdesc); - if (f == NULL) { - // LONGTERM - g_error("[libui] no match in pangoDescToPangoFont(); report to andlabs"); - } - g_object_unref(context); - return f; -} - -uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc) -{ - PangoFont *f; - PangoFontDescription *pdesc; - - pdesc = pango_font_description_new(); - pango_font_description_set_family(pdesc, - desc->Family); - pango_font_description_set_size(pdesc, - (gint) (desc->Size * PANGO_SCALE)); - pango_font_description_set_weight(pdesc, - pangoWeights[desc->Weight]); - pango_font_description_set_style(pdesc, - pangoItalics[desc->Italic]); - pango_font_description_set_stretch(pdesc, - pangoStretches[desc->Stretch]); - f = pangoDescToPangoFont(pdesc); - pango_font_description_free(pdesc); - return mkTextFont(f, FALSE); // we hold the initial reference; no need to ref -} - -void uiDrawFreeTextFont(uiDrawTextFont *font) -{ - g_object_unref(font->f); - uiFree(font); -} - -uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font) -{ - return (uintptr_t) (font->f); -} - -void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc) -{ - PangoFontDescription *pdesc; - - // this creates a copy; we free it later - pdesc = pango_font_describe(font->f); - - // TODO - - pango_font_description_free(pdesc); -} - -// See https://developer.gnome.org/pango/1.30/pango-Cairo-Rendering.html#pango-Cairo-Rendering.description -// Note that we convert to double before dividing to make sure the floating-point stuff is right -#define pangoToCairo(pango) (((double) (pango)) / PANGO_SCALE) -#define cairoToPango(cairo) ((gint) ((cairo) * PANGO_SCALE)) - -void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics) -{ - PangoFontMetrics *pm; - - pm = pango_font_get_metrics(font->f, NULL); - metrics->Ascent = pangoToCairo(pango_font_metrics_get_ascent(pm)); - metrics->Descent = pangoToCairo(pango_font_metrics_get_descent(pm)); - // Pango doesn't seem to expose this :( Use 0 and hope for the best. - metrics->Leading = 0; - metrics->UnderlinePos = pangoToCairo(pango_font_metrics_get_underline_position(pm)); - metrics->UnderlineThickness = pangoToCairo(pango_font_metrics_get_underline_thickness(pm)); - pango_font_metrics_unref(pm); -} - -// note: PangoCairoLayouts are tied to a given cairo_t, so we can't store one in this device-independent structure -struct uiDrawTextLayout { - char *s; - ptrdiff_t *graphemes; - PangoFont *defaultFont; - double width; - PangoAttrList *attrs; -}; - -uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width) -{ - uiDrawTextLayout *layout; - PangoContext *context; - - layout = uiNew(uiDrawTextLayout); - layout->s = g_strdup(text); - context = mkGenericPangoCairoContext(); - layout->graphemes = graphemes(layout->s, context); - g_object_unref(context); - layout->defaultFont = defaultFont->f; - g_object_ref(layout->defaultFont); // retain a copy - uiDrawTextLayoutSetWidth(layout, width); - layout->attrs = pango_attr_list_new(); - return layout; -} - -void uiDrawFreeTextLayout(uiDrawTextLayout *layout) -{ - pango_attr_list_unref(layout->attrs); - g_object_unref(layout->defaultFont); - uiFree(layout->graphemes); - g_free(layout->s); - uiFree(layout); -} - -void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width) -{ - layout->width = width; -} - -static void prepareLayout(uiDrawTextLayout *layout, PangoLayout *pl) -{ - PangoFontDescription *desc; - int width; - - pango_layout_set_text(pl, layout->s, -1); - - // again, this makes a copy - desc = pango_font_describe(layout->defaultFont); - // this is safe; the description is copied - pango_layout_set_font_description(pl, desc); - pango_font_description_free(desc); - - width = cairoToPango(layout->width); - if (layout->width < 0) - width = -1; - pango_layout_set_width(pl, width); - - pango_layout_set_attributes(pl, layout->attrs); -} - -void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height) -{ - PangoContext *context; - PangoLayout *pl; - PangoRectangle logical; - - // in this case, the context is necessary to create the layout - // the layout takes a ref on the context so we can unref it afterward - context = mkGenericPangoCairoContext(); - pl = pango_layout_new(context); - g_object_unref(context); - prepareLayout(layout, pl); - - pango_layout_get_extents(pl, NULL, &logical); - - g_object_unref(pl); - - *width = pangoToCairo(logical.width); - *height = pangoToCairo(logical.height); -} - -void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout) -{ - PangoLayout *pl; - - pl = pango_cairo_create_layout(c->cr); - prepareLayout(layout, pl); - - cairo_move_to(c->cr, x, y); - pango_cairo_show_layout(c->cr, pl); - - g_object_unref(pl); -} - -static void addAttr(uiDrawTextLayout *layout, PangoAttribute *attr, int startChar, int endChar) -{ - attr->start_index = layout->graphemes[startChar]; - attr->end_index = layout->graphemes[endChar]; - pango_attr_list_insert(layout->attrs, attr); - // pango_attr_list_insert() takes attr; we don't free it -} - -void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a) -{ - PangoAttribute *attr; - guint16 rr, gg, bb, aa; - - rr = (guint16) (r * 65535); - gg = (guint16) (g * 65535); - bb = (guint16) (b * 65535); - aa = (guint16) (a * 65535); - - attr = pango_attr_foreground_new(rr, gg, bb); - addAttr(layout, attr, startChar, endChar); - - // TODO what if aa == 0? - attr = FUTURE_pango_attr_foreground_alpha_new(aa); - if (attr != NULL) - addAttr(layout, attr, startChar, endChar); -} diff --git a/src/libui_sdl/libui/unix/editablecombo.c b/src/libui_sdl/libui/unix/editablecombo.c deleted file mode 100644 index 7ee3829..0000000 --- a/src/libui_sdl/libui/unix/editablecombo.c +++ /dev/null @@ -1,79 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiEditableCombobox { - uiUnixControl c; - GtkWidget *widget; - GtkBin *bin; - GtkComboBox *combobox; - GtkComboBoxText *comboboxText; - void (*onChanged)(uiEditableCombobox *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiEditableCombobox) - -static void onChanged(GtkComboBox *cbox, gpointer data) -{ - uiEditableCombobox *c = uiEditableCombobox(data); - - (*(c->onChanged))(c, c->onChangedData); -} - -static void defaultOnChanged(uiEditableCombobox *c, void *data) -{ - // do nothing -} - -void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text) -{ - gtk_combo_box_text_append(c->comboboxText, NULL, text); -} - -char *uiEditableComboboxText(uiEditableCombobox *c) -{ - char *s; - char *out; - - s = gtk_combo_box_text_get_active_text(c->comboboxText); - // s will always be non-NULL in the case of a combobox with an entry (according to the source code) - out = uiUnixStrdupText(s); - g_free(s); - return out; -} - -void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text) -{ - GtkEntry *e; - - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(c->combobox, c->onChangedSignal); - // since there isn't a gtk_combo_box_text_set_active_text()... - e = GTK_ENTRY(gtk_bin_get_child(c->bin)); - gtk_entry_set_text(e, text); - g_signal_handler_unblock(c->combobox, c->onChangedSignal); -} - -void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data) -{ - c->onChanged = f; - c->onChangedData = data; -} - -uiEditableCombobox *uiNewEditableCombobox(void) -{ - uiEditableCombobox *c; - - uiUnixNewControl(uiEditableCombobox, c); - - c->widget = gtk_combo_box_text_new_with_entry(); - c->bin = GTK_BIN(c->widget); - c->combobox = GTK_COMBO_BOX(c->widget); - c->comboboxText = GTK_COMBO_BOX_TEXT(c->widget); - - c->onChangedSignal = g_signal_connect(c->widget, "changed", G_CALLBACK(onChanged), c); - uiEditableComboboxOnChanged(c, defaultOnChanged, NULL); - - return c; -} diff --git a/src/libui_sdl/libui/unix/entry.c b/src/libui_sdl/libui/unix/entry.c deleted file mode 100644 index 4a9a1d0..0000000 --- a/src/libui_sdl/libui/unix/entry.c +++ /dev/null @@ -1,97 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiEntry { - uiUnixControl c; - GtkWidget *widget; - GtkEntry *entry; - GtkEditable *editable; - void (*onChanged)(uiEntry *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiEntry) - -static void onChanged(GtkEditable *editable, gpointer data) -{ - uiEntry *e = uiEntry(data); - - (*(e->onChanged))(e, e->onChangedData); -} - -static void defaultOnChanged(uiEntry *e, void *data) -{ - // do nothing -} - -char *uiEntryText(uiEntry *e) -{ - return uiUnixStrdupText(gtk_entry_get_text(e->entry)); -} - -void uiEntrySetText(uiEntry *e, const char *text) -{ - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(e->editable, e->onChangedSignal); - gtk_entry_set_text(e->entry, text); - g_signal_handler_unblock(e->editable, e->onChangedSignal); - // don't queue the control for resize; entry sizes are independent of their contents -} - -void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiEntryReadOnly(uiEntry *e) -{ - return gtk_editable_get_editable(e->editable) == FALSE; -} - -void uiEntrySetReadOnly(uiEntry *e, int readonly) -{ - gboolean editable; - - editable = TRUE; - if (readonly) - editable = FALSE; - gtk_editable_set_editable(e->editable, editable); -} - -static uiEntry *finishNewEntry(GtkWidget *w, const gchar *signal) -{ - uiEntry *e; - - uiUnixNewControl(uiEntry, e); - - e->widget = w; - e->entry = GTK_ENTRY(e->widget); - e->editable = GTK_EDITABLE(e->widget); - - e->onChangedSignal = g_signal_connect(e->widget, signal, G_CALLBACK(onChanged), e); - uiEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiEntry *uiNewEntry(void) -{ - return finishNewEntry(gtk_entry_new(), "changed"); -} - -uiEntry *uiNewPasswordEntry(void) -{ - GtkWidget *e; - - e = gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(e), FALSE); - return finishNewEntry(e, "changed"); -} - -// TODO make it use a separate function to be type-safe -uiEntry *uiNewSearchEntry(void) -{ - return finishNewEntry(gtk_search_entry_new(), "search-changed"); -} diff --git a/src/libui_sdl/libui/unix/fontbutton.c b/src/libui_sdl/libui/unix/fontbutton.c deleted file mode 100644 index f8047e0..0000000 --- a/src/libui_sdl/libui/unix/fontbutton.c +++ /dev/null @@ -1,70 +0,0 @@ -// 14 april 2016 -#include "uipriv_unix.h" - -struct uiFontButton { - uiUnixControl c; - GtkWidget *widget; - GtkButton *button; - GtkFontButton *fb; - GtkFontChooser *fc; - void (*onChanged)(uiFontButton *, void *); - void *onChangedData; -}; - -uiUnixControlAllDefaults(uiFontButton) - -// TODO NOTE no need to inhibit the signal; font-set is documented as only being sent when the user changes the font -static void onFontSet(GtkFontButton *button, gpointer data) -{ - uiFontButton *b = uiFontButton(data); - - (*(b->onChanged))(b, b->onChangedData); -} - -static void defaultOnChanged(uiFontButton *b, void *data) -{ - // do nothing -} - -uiDrawTextFont *uiFontButtonFont(uiFontButton *b) -{ - PangoFont *f; - PangoFontDescription *desc; - - desc = gtk_font_chooser_get_font_desc(b->fc); - f = pangoDescToPangoFont(desc); - // desc is transfer-full and thus is a copy - pango_font_description_free(desc); - return mkTextFont(f, FALSE); // we hold the initial reference; no need to ref -} - -void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiFontButton *uiNewFontButton(void) -{ - uiFontButton *b; - - uiUnixNewControl(uiFontButton, b); - - b->widget = gtk_font_button_new(); - b->button = GTK_BUTTON(b->widget); - b->fb = GTK_FONT_BUTTON(b->widget); - b->fc = GTK_FONT_CHOOSER(b->widget); - - // match behavior on other platforms - gtk_font_button_set_show_style(b->fb, TRUE); - gtk_font_button_set_show_size(b->fb, TRUE); - gtk_font_button_set_use_font(b->fb, FALSE); - gtk_font_button_set_use_size(b->fb, FALSE); - // other customizations - gtk_font_chooser_set_show_preview_entry(b->fc, TRUE); - - g_signal_connect(b->widget, "font-set", G_CALLBACK(onFontSet), b); - uiFontButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/src/libui_sdl/libui/unix/form.c b/src/libui_sdl/libui/unix/form.c deleted file mode 100644 index 54422b3..0000000 --- a/src/libui_sdl/libui/unix/form.c +++ /dev/null @@ -1,159 +0,0 @@ -// 8 june 2016 -#include "uipriv_unix.h" - -struct formChild { - uiControl *c; - int stretchy; - GtkWidget *label; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; - GBinding *labelBinding; -}; - -struct uiForm { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkGrid *grid; - GArray *children; - int padded; - GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size -}; - -uiUnixControlAllDefaultsExceptDestroy(uiForm) - -#define ctrl(f, i) &g_array_index(f->children, struct formChild, i) - -static void uiFormDestroy(uiControl *c) -{ - uiForm *f = uiForm(c); - struct formChild *fc; - guint i; - - // kill the size group - g_object_unref(f->stretchygroup); - // free all controls - for (i = 0; i < f->children->len; i++) { - fc = ctrl(f, i); - uiControlSetParent(fc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); - uiControlDestroy(fc->c); - gtk_widget_destroy(fc->label); - } - g_array_free(f->children, TRUE); - // and then ourselves - g_object_unref(f->widget); - uiFreeControl(uiControl(f)); -} - -void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) -{ - struct formChild fc; - GtkWidget *widget; - guint row; - - fc.c = c; - widget = GTK_WIDGET(uiControlHandle(fc.c)); - fc.stretchy = stretchy; - fc.oldhexpand = gtk_widget_get_hexpand(widget); - fc.oldhalign = gtk_widget_get_halign(widget); - fc.oldvexpand = gtk_widget_get_vexpand(widget); - fc.oldvalign = gtk_widget_get_valign(widget); - - if (stretchy) { - gtk_widget_set_vexpand(widget, TRUE); - gtk_widget_set_valign(widget, GTK_ALIGN_FILL); - gtk_size_group_add_widget(f->stretchygroup, widget); - } else - gtk_widget_set_vexpand(widget, FALSE); - // and make them fill horizontally - gtk_widget_set_hexpand(widget, TRUE); - gtk_widget_set_halign(widget, GTK_ALIGN_FILL); - - fc.label = gtk_label_new(label); - gtk_widget_set_hexpand(fc.label, FALSE); - gtk_widget_set_halign(fc.label, GTK_ALIGN_END); - gtk_widget_set_vexpand(fc.label, FALSE); - if (GTK_IS_SCROLLED_WINDOW(widget)) - gtk_widget_set_valign(fc.label, GTK_ALIGN_START); - else - gtk_widget_set_valign(fc.label, GTK_ALIGN_CENTER); - gtk_style_context_add_class(gtk_widget_get_style_context(fc.label), "dim-label"); - row = f->children->len; - gtk_grid_attach(f->grid, fc.label, - 0, row, - 1, 1); - // and make them share visibility so if the control is hidden, so is its label - fc.labelBinding = g_object_bind_property(GTK_WIDGET(uiControlHandle(fc.c)), "visible", - fc.label, "visible", - G_BINDING_SYNC_CREATE); - - uiControlSetParent(fc.c, uiControl(f)); - uiUnixControlSetContainer(uiUnixControl(fc.c), f->container, FALSE); - g_array_append_val(f->children, fc); - - // move the widget to the correct place - gtk_container_child_set(f->container, widget, - "left-attach", 1, - "top-attach", row, - NULL); -} - -void uiFormDelete(uiForm *f, int index) -{ - struct formChild *fc; - GtkWidget *widget; - - fc = ctrl(f, index); - widget = GTK_WIDGET(uiControlHandle(fc->c)); - - gtk_widget_destroy(fc->label); - - uiControlSetParent(fc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); - - if (fc->stretchy) - gtk_size_group_remove_widget(f->stretchygroup, widget); - gtk_widget_set_hexpand(widget, fc->oldhexpand); - gtk_widget_set_halign(widget, fc->oldhalign); - gtk_widget_set_vexpand(widget, fc->oldvexpand); - gtk_widget_set_valign(widget, fc->oldvalign); - - g_array_remove_index(f->children, index); -} - -int uiFormPadded(uiForm *f) -{ - return f->padded; -} - -void uiFormSetPadded(uiForm *f, int padded) -{ - f->padded = padded; - if (f->padded) { - gtk_grid_set_row_spacing(f->grid, gtkYPadding); - gtk_grid_set_column_spacing(f->grid, gtkXPadding); - } else { - gtk_grid_set_row_spacing(f->grid, 0); - gtk_grid_set_column_spacing(f->grid, 0); - } -} - -uiForm *uiNewForm(void) -{ - uiForm *f; - - uiUnixNewControl(uiForm, f); - - f->widget = gtk_grid_new(); - f->container = GTK_CONTAINER(f->widget); - f->grid = GTK_GRID(f->widget); - - f->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); - - f->children = g_array_new(FALSE, TRUE, sizeof (struct formChild)); - - return f; -} diff --git a/src/libui_sdl/libui/unix/future.c b/src/libui_sdl/libui/unix/future.c deleted file mode 100644 index 1f9f532..0000000 --- a/src/libui_sdl/libui/unix/future.c +++ /dev/null @@ -1,42 +0,0 @@ -// 29 june 2016 -#include "uipriv_unix.h" - -// functions FROM THE FUTURE! -// in some cases, because being held back by LTS releases sucks :/ -// in others, because parts of GTK+ being unstable until recently also sucks :/ - -// added in pango 1.38; we need 1.36 -static PangoAttribute *(*newFGAlphaAttr)(guint16 alpha) = NULL; - -// added in GTK+ 3.20; we need 3.10 -static void (*gwpIterSetObjectName)(GtkWidgetPath *path, gint pos, const char *name) = NULL; - -// note that we treat any error as "the symbols aren't there" (and don't care if dlclose() failed) -void loadFutures(void) -{ - void *handle; - - // dlsym() walks the dependency chain, so opening the current process should be sufficient - handle = dlopen(NULL, RTLD_LAZY); - if (handle == NULL) - return; -#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn) - GET(newFGAlphaAttr, pango_attr_foreground_alpha_new); - GET(gwpIterSetObjectName, gtk_widget_path_iter_set_object_name); - dlclose(handle); -} - -PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha) -{ - if (newFGAlphaAttr == NULL) - return NULL; - return (*newFGAlphaAttr)(alpha); -} - -gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name) -{ - if (gwpIterSetObjectName == NULL) - return FALSE; - (*gwpIterSetObjectName)(path, pos, name); - return TRUE; -} diff --git a/src/libui_sdl/libui/unix/gl.c b/src/libui_sdl/libui/unix/gl.c deleted file mode 100644 index e15cf4f..0000000 --- a/src/libui_sdl/libui/unix/gl.c +++ /dev/null @@ -1,251 +0,0 @@ -// 26 may 2019 -#include "uipriv_unix.h" - -#include <GL/gl.h> -#include <GL/glx.h> -#include <EGL/egl.h> - -extern GThread* gtkthread; -extern GMutex glmutex; - -struct uiGLContext -{ - GtkWidget* widget; - GdkWindow* window; - - GdkGLContext *gctx; - int vermaj, vermin; - - int width, height; - int scale; - GLuint renderbuffer[2][2]; - GLuint framebuffer[2]; - int backbuffer; -}; - -static void areaAllocRenderbuffer(uiGLContext* glctx); - -static PFNGLGENRENDERBUFFERSPROC _glGenRenderbuffers; -static PFNGLDELETERENDERBUFFERSPROC _glDeleteRenderbuffers; -static PFNGLBINDRENDERBUFFERPROC _glBindRenderbuffer; -static PFNGLRENDERBUFFERSTORAGEPROC _glRenderbufferStorage; -static PFNGLGETRENDERBUFFERPARAMETERIVPROC _glGetRenderbufferParameteriv; - -static PFNGLGENRENDERBUFFERSPROC _glGenFramebuffers; -static PFNGLDELETERENDERBUFFERSPROC _glDeleteFramebuffers; -static PFNGLBINDRENDERBUFFERPROC _glBindFramebuffer; -static PFNGLFRAMEBUFFERTEXTUREPROC _glFramebufferTexture; -static PFNGLFRAMEBUFFERRENDERBUFFERPROC _glFramebufferRenderbuffer; -static PFNGLCHECKFRAMEBUFFERSTATUSPROC _glCheckFramebufferStatus; - -static int _procsLoaded = 0; - -static void _loadGLProcs(GdkGLContext* glctx) -{ - if (_procsLoaded) return; - - _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)uiGLGetProcAddress("glGenRenderbuffers"); - _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)uiGLGetProcAddress("glDeleteRenderbuffers"); - _glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)uiGLGetProcAddress("glBindRenderbuffer"); - _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)uiGLGetProcAddress("glRenderbufferStorage"); - _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)uiGLGetProcAddress("glGetRenderbufferParameteriv"); - - _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)uiGLGetProcAddress("glGenFramebuffers"); - _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)uiGLGetProcAddress("glDeleteFramebuffers"); - _glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)uiGLGetProcAddress("glBindFramebuffer"); - _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)uiGLGetProcAddress("glFramebufferTexture"); - _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)uiGLGetProcAddress("glFramebufferRenderbuffer"); - _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)uiGLGetProcAddress("glCheckFramebufferStatus"); - - _procsLoaded = 1; -} - -uiGLContext *createGLContext(GtkWidget* widget, int maj, int min) -{ - GdkWindow* gdkwin = gtk_widget_get_window(widget); - - GError* err = NULL; - GdkGLContext* gctx = gdk_window_create_gl_context(gdkwin, &err); - if (err != NULL || gctx == NULL) - { - return NULL; - } - - // TODO: make the set_use_es call conditional (#ifdef or smth) for older versions of gdk? - gdk_gl_context_set_use_es(gctx, FALSE); - gdk_gl_context_set_required_version(gctx, maj, min); - - gboolean res = gdk_gl_context_realize(gctx, &err); - if (err != NULL || res == FALSE) - { - return NULL; - } - - uiGLContext* ctx = uiNew(uiGLContext); - - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - int window_scale = gdk_window_get_scale_factor(gdkwin); - ctx->width = allocation.width; - ctx->height = allocation.height; - ctx->scale = window_scale; - - gdk_gl_context_make_current(gctx); - _loadGLProcs(gctx); - areaAllocRenderbuffer(ctx); - ctx->backbuffer = 0; - - ctx->widget = widget; - ctx->window = gdkwin; - ctx->gctx = gctx; - - return ctx; -} - -void freeGLContext(uiGLContext* glctx) -{ - if (glctx == NULL) return; - - gdk_gl_context_make_current(glctx->gctx); - _glDeleteRenderbuffers(4, &glctx->renderbuffer[0][0]); - _glDeleteFramebuffers(2, &glctx->framebuffer[0]); - - gdk_gl_context_clear_current(); - g_object_unref(glctx->gctx); - uiFree(glctx); -} - -static void areaAllocRenderbuffer(uiGLContext* glctx) -{ - // TODO: create textures as a fallback if GL_RGB renderbuffer isn't supported? - // they say GL implementations aren't required to support a GL_RGB renderbuffer - // however, a GL_RGBA one would cause gdk_cairo_draw_from_gl() to fall back to glReadPixels() - - _glGenRenderbuffers(4, &glctx->renderbuffer[0][0]); - _glGenFramebuffers(2, &glctx->framebuffer[0]); - - _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]); - _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); - //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]); - //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); - - _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]); - _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]); - _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]); - - _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]); - _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); - //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]); - //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); - - _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]); - _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]); - _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]); - - //if (_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - // printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER)); -} - -static void areaReallocRenderbuffer(uiGLContext* glctx) -{ - _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]); - _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); - //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]); - //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); - - _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]); - _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); - //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]); - //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); -} - -void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx) -{ - int window_scale = gdk_window_get_scale_factor(glctx->window); - - if (glctx->width != dp->AreaWidth || glctx->height != dp->AreaHeight || glctx->scale != window_scale) - { - glctx->width = dp->AreaWidth; - glctx->height = dp->AreaHeight; - glctx->scale = window_scale; - areaReallocRenderbuffer(glctx); - } - else - { - gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget), - glctx->renderbuffer[glctx->backbuffer][0], GL_RENDERBUFFER, - 1, 0, 0, glctx->width*glctx->scale, glctx->height*glctx->scale); - } -} - -int uiGLGetFramebuffer(uiGLContext* ctx) -{ - return ctx->framebuffer[ctx->backbuffer]; -} - -float uiGLGetFramebufferScale(uiGLContext* ctx) -{ - return (float)ctx->scale; -} - -void uiGLSwapBuffers(uiGLContext* ctx) -{ - ctx->backbuffer = ctx->backbuffer ? 0 : 1; -} - -void uiGLSetVSync(int sync) -{ - // TODO -} - -void uiGLMakeContextCurrent(uiGLContext* ctx) -{ - if (!ctx) - { - gdk_gl_context_clear_current(); - return; - } - - if (ctx->gctx == gdk_gl_context_get_current()) return; - gdk_gl_context_make_current(ctx->gctx); -} - -void uiGLBegin(uiGLContext* ctx) -{ - if (g_thread_self() != gtkthread) - { - g_mutex_lock(&glmutex); - } -} - -void uiGLEnd(uiGLContext* ctx) -{ - if (g_thread_self() != gtkthread) - { - g_mutex_unlock(&glmutex); - } -} - -void *uiGLGetProcAddress(const char* proc) -{ - // TODO: consider using epoxy or something funny - - void* ptr; - - ptr = glXGetProcAddressARB((const GLubyte*)proc); - if (ptr) return ptr; - - ptr = eglGetProcAddress(proc); - if (ptr) return ptr; - - ptr = dlsym(NULL /* RTLD_DEFAULT */, proc); - if (ptr) return ptr; - - return NULL; -} -unsigned int uiGLGetVersion(uiGLContext* ctx) -{ - if (!ctx) return 0; - return uiGLVersion(ctx->vermaj, ctx->vermin); -} - diff --git a/src/libui_sdl/libui/unix/graphemes.c b/src/libui_sdl/libui/unix/graphemes.c deleted file mode 100644 index a2c47b7..0000000 --- a/src/libui_sdl/libui/unix/graphemes.c +++ /dev/null @@ -1,31 +0,0 @@ -// 25 may 2016 -#include "uipriv_unix.h" - -ptrdiff_t *graphemes(const char *text, PangoContext *context) -{ - size_t len, lenchars; - PangoLogAttr *logattrs; - ptrdiff_t *out; - ptrdiff_t *op; - size_t i; - - len = strlen(text); - lenchars = g_utf8_strlen(text, -1); - logattrs = (PangoLogAttr *) uiAlloc((lenchars + 1) * sizeof (PangoLogAttr), "PangoLogAttr[]"); - pango_get_log_attrs(text, len, - -1, NULL, - logattrs, lenchars + 1); - - // should be more than enough - out = (ptrdiff_t *) uiAlloc((lenchars + 2) * sizeof (ptrdiff_t), "ptrdiff_t[]"); - op = out; - for (i = 0; i < lenchars; i++) - if (logattrs[i].is_cursor_position != 0) - // TODO optimize this - *op++ = g_utf8_offset_to_pointer(text, i) - text; - // and do the last one - *op++ = len; - - uiFree(logattrs); - return out; -} diff --git a/src/libui_sdl/libui/unix/grid.c b/src/libui_sdl/libui/unix/grid.c deleted file mode 100644 index 6d9813b..0000000 --- a/src/libui_sdl/libui/unix/grid.c +++ /dev/null @@ -1,141 +0,0 @@ -// 9 june 2016 -#include "uipriv_unix.h" - -struct gridChild { - uiControl *c; - GtkWidget *label; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; -}; - -struct uiGrid { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkGrid *grid; - GArray *children; - int padded; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiGrid) - -#define ctrl(g, i) &g_array_index(g->children, struct gridChild, i) - -static void uiGridDestroy(uiControl *c) -{ - uiGrid *g = uiGrid(c); - struct gridChild *gc; - guint i; - - // free all controls - for (i = 0; i < g->children->len; i++) { - gc = ctrl(g, i); - uiControlSetParent(gc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(gc->c), g->container, TRUE); - uiControlDestroy(gc->c); - } - g_array_free(g->children, TRUE); - // and then ourselves - g_object_unref(g->widget); - uiFreeControl(uiControl(g)); -} - -#define TODO_MASSIVE_HACK(c) \ - if (!uiUnixControl(c)->addedBefore) { \ - g_object_ref_sink(GTK_WIDGET(uiControlHandle(uiControl(c)))); \ - gtk_widget_show(GTK_WIDGET(uiControlHandle(uiControl(c)))); \ - uiUnixControl(c)->addedBefore = TRUE; \ - } - -static const GtkAlign gtkAligns[] = { - [uiAlignFill] = GTK_ALIGN_FILL, - [uiAlignStart] = GTK_ALIGN_START, - [uiAlignCenter] = GTK_ALIGN_CENTER, - [uiAlignEnd] = GTK_ALIGN_END, -}; - -static const GtkPositionType gtkPositions[] = { - [uiAtLeading] = GTK_POS_LEFT, - [uiAtTop] = GTK_POS_TOP, - [uiAtTrailing] = GTK_POS_RIGHT, - [uiAtBottom] = GTK_POS_BOTTOM, -}; - -static GtkWidget *prepare(struct gridChild *gc, uiControl *c, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - GtkWidget *widget; - - gc->c = c; - widget = GTK_WIDGET(uiControlHandle(gc->c)); - gc->oldhexpand = gtk_widget_get_hexpand(widget); - gc->oldhalign = gtk_widget_get_halign(widget); - gc->oldvexpand = gtk_widget_get_vexpand(widget); - gc->oldvalign = gtk_widget_get_valign(widget); - gtk_widget_set_hexpand(widget, hexpand != 0); - gtk_widget_set_halign(widget, gtkAligns[halign]); - gtk_widget_set_vexpand(widget, vexpand != 0); - gtk_widget_set_valign(widget, gtkAligns[valign]); - return widget; -} - -void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild gc; - GtkWidget *widget; - - widget = prepare(&gc, c, hexpand, halign, vexpand, valign); - uiControlSetParent(gc.c, uiControl(g)); - TODO_MASSIVE_HACK(uiUnixControl(gc.c)); - gtk_grid_attach(g->grid, widget, - left, top, - xspan, yspan); - g_array_append_val(g->children, gc); -} - -void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - struct gridChild gc; - GtkWidget *widget; - - widget = prepare(&gc, c, hexpand, halign, vexpand, valign); - uiControlSetParent(gc.c, uiControl(g)); - TODO_MASSIVE_HACK(uiUnixControl(gc.c)); - gtk_grid_attach_next_to(g->grid, widget, - GTK_WIDGET(uiControlHandle(existing)), gtkPositions[at], - xspan, yspan); - g_array_append_val(g->children, gc); -} - -int uiGridPadded(uiGrid *g) -{ - return g->padded; -} - -void uiGridSetPadded(uiGrid *g, int padded) -{ - g->padded = padded; - if (g->padded) { - gtk_grid_set_row_spacing(g->grid, gtkYPadding); - gtk_grid_set_column_spacing(g->grid, gtkXPadding); - } else { - gtk_grid_set_row_spacing(g->grid, 0); - gtk_grid_set_column_spacing(g->grid, 0); - } -} - -uiGrid *uiNewGrid(void) -{ - uiGrid *g; - - uiUnixNewControl(uiGrid, g); - - g->widget = gtk_grid_new(); - g->container = GTK_CONTAINER(g->widget); - g->grid = GTK_GRID(g->widget); - - g->children = g_array_new(FALSE, TRUE, sizeof (struct gridChild)); - - return g; -} diff --git a/src/libui_sdl/libui/unix/group.c b/src/libui_sdl/libui/unix/group.c deleted file mode 100644 index 6238a1b..0000000 --- a/src/libui_sdl/libui/unix/group.c +++ /dev/null @@ -1,89 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiGroup { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBin *bin; - GtkFrame *frame; - - // unfortunately, even though a GtkFrame is a GtkBin, calling gtk_container_set_border_width() on it /includes/ the GtkFrame's label; we don't want tht - struct child *child; - - int margined; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiGroup) - -static void uiGroupDestroy(uiControl *c) -{ - uiGroup *g = uiGroup(c); - - if (g->child != NULL) - childDestroy(g->child); - g_object_unref(g->widget); - uiFreeControl(uiControl(g)); -} - -char *uiGroupTitle(uiGroup *g) -{ - return uiUnixStrdupText(gtk_frame_get_label(g->frame)); -} - -void uiGroupSetTitle(uiGroup *g, const char *text) -{ - gtk_frame_set_label(g->frame, text); -} - -void uiGroupSetChild(uiGroup *g, uiControl *child) -{ - if (g->child != NULL) - childRemove(g->child); - g->child = newChildWithBox(child, uiControl(g), g->container, g->margined); -} - -int uiGroupMargined(uiGroup *g) -{ - return g->margined; -} - -void uiGroupSetMargined(uiGroup *g, int margined) -{ - g->margined = margined; - if (g->child != NULL) - childSetMargined(g->child, g->margined); -} - -uiGroup *uiNewGroup(const char *text) -{ - uiGroup *g; - gfloat yalign; - GtkLabel *label; - PangoAttribute *bold; - PangoAttrList *boldlist; - - uiUnixNewControl(uiGroup, g); - - g->widget = gtk_frame_new(text); - g->container = GTK_CONTAINER(g->widget); - g->bin = GTK_BIN(g->widget); - g->frame = GTK_FRAME(g->widget); - - // with GTK+, groupboxes by default have frames and slightly x-offset regular text - // they should have no frame and fully left-justified, bold text - // preserve default y-alignment - gtk_frame_get_label_align(g->frame, NULL, &yalign); - gtk_frame_set_label_align(g->frame, 0, yalign); - gtk_frame_set_shadow_type(g->frame, GTK_SHADOW_NONE); - label = GTK_LABEL(gtk_frame_get_label_widget(g->frame)); - // this is the boldness level used by GtkPrintUnixDialog - // (it technically uses "bold" but see pango's pango-enum-types.c for the name conversion; GType is weird) - bold = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - boldlist = pango_attr_list_new(); - pango_attr_list_insert(boldlist, bold); - gtk_label_set_attributes(label, boldlist); - pango_attr_list_unref(boldlist); // thanks baedert in irc.gimp.net/#gtk+ - - return g; -} diff --git a/src/libui_sdl/libui/unix/image.c b/src/libui_sdl/libui/unix/image.c deleted file mode 100644 index a79e550..0000000 --- a/src/libui_sdl/libui/unix/image.c +++ /dev/null @@ -1,120 +0,0 @@ -// 27 june 2016 -#include "uipriv_unix.h" - -struct uiImage { - double width; - double height; - GPtrArray *images; -}; - -static void freeImageRep(gpointer item) -{ - cairo_surface_t *cs = (cairo_surface_t *) item; - unsigned char *buf; - - buf = cairo_image_surface_get_data(cs); - cairo_surface_destroy(cs); - uiFree(buf); -} - -uiImage *uiNewImage(double width, double height) -{ - uiImage *i; - - i = uiNew(uiImage); - i->width = width; - i->height = height; - i->images = g_ptr_array_new_with_free_func(freeImageRep); - return i; -} - -void uiFreeImage(uiImage *i) -{ - g_ptr_array_free(i->images, TRUE); - uiFree(i); -} - -void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride) -{ - cairo_surface_t *cs; - unsigned char *buf, *p; - uint8_t *src = (uint8_t *) pixels; - int cstride; - int y; - - cstride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixelWidth); - buf = (unsigned char *) uiAlloc((cstride * pixelHeight * 4) * sizeof (unsigned char), "unsigned char[]"); - p = buf; - for (y = 0; y < pixelStride * pixelHeight; y += pixelStride) { - memmove(p, src + y, cstride); - p += cstride; - } - cs = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, - pixelWidth, pixelHeight, - cstride); - if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) - /* TODO */; - cairo_surface_flush(cs); - g_ptr_array_add(i->images, cs); -} - -struct matcher { - cairo_surface_t *best; - int distX; - int distY; - int targetX; - int targetY; - gboolean foundLarger; -}; - -// TODO is this the right algorithm? -static void match(gpointer surface, gpointer data) -{ - cairo_surface_t *cs = (cairo_surface_t *) surface; - struct matcher *m = (struct matcher *) data; - int x, y; - int x2, y2; - - x = cairo_image_surface_get_width(cs); - y = cairo_image_surface_get_height(cs); - if (m->best == NULL) - goto writeMatch; - - if (x < m->targetX && y < m->targetY) - if (m->foundLarger) - // always prefer larger ones - return; - if (x >= m->targetX && y >= m->targetY && !m->foundLarger) - // we set foundLarger below - goto writeMatch; - - x2 = abs(m->targetX - x); - y2 = abs(m->targetY - y); - if (x2 < m->distX && y2 < m->distY) - goto writeMatch; - - // TODO weight one dimension? threshhold? - return; - -writeMatch: - // must set this here too; otherwise the first image will never have ths set - if (x >= m->targetX && y >= m->targetY && !m->foundLarger) - m->foundLarger = TRUE; - m->best = cs; - m->distX = abs(m->targetX - x); - m->distY = abs(m->targetY - y); -} - -cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w) -{ - struct matcher m; - - m.best = NULL; - m.distX = G_MAXINT; - m.distY = G_MAXINT; - m.targetX = i->width * gtk_widget_get_scale_factor(w); - m.targetY = i->height * gtk_widget_get_scale_factor(w); - m.foundLarger = FALSE; - g_ptr_array_foreach(i->images, match, &m); - return m.best; -} diff --git a/src/libui_sdl/libui/unix/label.c b/src/libui_sdl/libui/unix/label.c deleted file mode 100644 index b39fc7c..0000000 --- a/src/libui_sdl/libui/unix/label.c +++ /dev/null @@ -1,36 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiLabel { - uiUnixControl c; - GtkWidget *widget; - GtkMisc *misc; - GtkLabel *label; -}; - -uiUnixControlAllDefaults(uiLabel) - -char *uiLabelText(uiLabel *l) -{ - return uiUnixStrdupText(gtk_label_get_text(l->label)); -} - -void uiLabelSetText(uiLabel *l, const char *text) -{ - gtk_label_set_text(l->label, text); -} - -uiLabel *uiNewLabel(const char *text) -{ - uiLabel *l; - - uiUnixNewControl(uiLabel, l); - - l->widget = gtk_label_new(text); - l->misc = GTK_MISC(l->widget); - l->label = GTK_LABEL(l->widget); - - gtk_misc_set_alignment(l->misc, 0, 0); - - return l; -} diff --git a/src/libui_sdl/libui/unix/main.c b/src/libui_sdl/libui/unix/main.c deleted file mode 100644 index 516bd76..0000000 --- a/src/libui_sdl/libui/unix/main.c +++ /dev/null @@ -1,147 +0,0 @@ -// 6 april 2015 -#include "uipriv_unix.h" - -uiInitOptions options; - -// kind of a hack -GThread* gtkthread; -GMutex glmutex; - -static void _eventfilter(GdkEvent* evt, gpointer data) -{ - if (evt->type == GDK_EXPOSE) - { - g_mutex_lock(&glmutex); - gtk_main_do_event(evt); - g_mutex_unlock(&glmutex); - return; - } - - gtk_main_do_event(evt); -} - -static void _eventfilterdestroy(gpointer data) -{ - printf("DELET\n"); -} - -const char *uiInit(uiInitOptions *o) -{ - GError *err = NULL; - const char *msg; - - options = *o; - if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) { - msg = g_strdup(err->message); - g_error_free(err); - return msg; - } - initAlloc(); - loadFutures(); - - gtkthread = g_thread_self(); - g_mutex_init(&glmutex); - - GList* iconlist = NULL; - iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_16x16.png", NULL)); - iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_32x32.png", NULL)); - iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_48x48.png", NULL)); - iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_64x64.png", NULL)); - iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_128x128.png", NULL)); - - gtk_window_set_default_icon_list(iconlist); - - g_mutex_init(&glmutex); - - gdk_event_handler_set(_eventfilter, NULL, _eventfilterdestroy); - - return NULL; -} - -void uiUninit(void) -{ - uninitMenus(); - uninitAlloc(); -} - -void uiFreeInitError(const char *err) -{ - g_free((gpointer) err); -} - -static gboolean (*iteration)(gboolean) = NULL; - -void uiMain(void) -{ - iteration = gtk_main_iteration_do; - gtk_main(); -} - -static gboolean stepsQuit = FALSE; - -// the only difference is we ignore the return value from gtk_main_iteration_do(), since it will always be TRUE if gtk_main() was never called -// gtk_main_iteration_do() will still run the main loop regardless -static gboolean stepsIteration(gboolean block) -{ - gtk_main_iteration_do(block); - return stepsQuit; -} - -void uiMainSteps(void) -{ - iteration = stepsIteration; -} - -int uiMainStep(int wait) -{ - gboolean block; - - block = FALSE; - if (wait) - block = TRUE; - return (*iteration)(block) == FALSE; -} - -// gtk_main_quit() may run immediately, or it may wait for other pending events; "it depends" (thanks mclasen in irc.gimp.net/#gtk+) -// PostQuitMessage() on Windows always waits, so we must do so too -// we'll do it by using an idle callback -static gboolean quit(gpointer data) -{ - if (iteration == stepsIteration) - stepsQuit = TRUE; - // TODO run a gtk_main() here just to do the cleanup steps of syncing the clipboard and other stuff gtk_main() does before it returns - else - gtk_main_quit(); - return FALSE; -} - -void uiQuit(void) -{ - gdk_threads_add_idle(quit, NULL); -} - -struct queued { - void (*f)(void *); - void *data; -}; - -static gboolean doqueued(gpointer data) -{ - struct queued *q = (struct queued *) data; - - (*(q->f))(q->data); - g_free(q); - return FALSE; -} - -void uiQueueMain(void (*f)(void *data), void *data) -{ - struct queued *q; - - // we have to use g_new0()/g_free() because uiAlloc() is only safe to call on the main thread - // for some reason it didn't affect me, but it did affect krakjoe - q = g_new0(struct queued, 1); - q->f = f; - q->data = data; - gdk_threads_add_idle(doqueued, q); -} diff --git a/src/libui_sdl/libui/unix/menu.c b/src/libui_sdl/libui/unix/menu.c deleted file mode 100644 index d641426..0000000 --- a/src/libui_sdl/libui/unix/menu.c +++ /dev/null @@ -1,432 +0,0 @@ -// 23 april 2015 -#include "uipriv_unix.h" - -static GArray *menus = NULL; -static guint nmenus = 0; -static gboolean menusFinalized = FALSE; -static gboolean hasQuit = FALSE; -static gboolean hasPreferences = FALSE; -static gboolean hasAbout = FALSE; - -struct uiMenu { - char *name; - GArray *items; // []*uiMenuItem - gboolean ischild; - guint id; -}; - -struct uiMenuItem { - char *name; - int type; - void (*onClicked)(uiMenuItem *, uiWindow *, void *); - void *onClickedData; - GType gtype; // template for new instances; kept in sync with everything else - gboolean disabled; - gboolean checked; - GHashTable *windows; // map[GtkMenuItem]*menuItemWindow - uiMenu *popupchild; -}; - -struct menuItemWindow { - uiWindow *w; - gulong signal; -}; - -enum { - typeRegular, - typeCheckbox, - typeQuit, - typePreferences, - typeAbout, - typeSeparator, - typeSubmenu, -}; - -// we do NOT want programmatic updates to raise an ::activated signal -static void singleSetChecked(GtkCheckMenuItem *menuitem, gboolean checked, gulong signal) -{ - g_signal_handler_block(menuitem, signal); - gtk_check_menu_item_set_active(menuitem, checked); - g_signal_handler_unblock(menuitem, signal); -} - -static void setChecked(uiMenuItem *item, gboolean checked) -{ - GHashTableIter iter; - gpointer widget; - gpointer ww; - struct menuItemWindow *w; - - item->checked = checked; - g_hash_table_iter_init(&iter, item->windows); - while (g_hash_table_iter_next(&iter, &widget, &ww)) { - w = (struct menuItemWindow *) ww; - singleSetChecked(GTK_CHECK_MENU_ITEM(widget), item->checked, w->signal); - } -} - -static void onClicked(GtkMenuItem *menuitem, gpointer data) -{ - uiMenuItem *item = uiMenuItem(data); - struct menuItemWindow *w; - - // we need to manually update the checked states of all menu items if one changes - // notice that this is getting the checked state of the menu item that this signal is sent from - if (item->type == typeCheckbox) - setChecked(item, gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))); - - w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, menuitem); - (*(item->onClicked))(item, w->w, item->onClickedData); -} - -static void defaultOnClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - // do nothing -} - -static void onQuitClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - if (shouldQuit()) - uiQuit(); -} - -static void menuItemEnableDisable(uiMenuItem *item, gboolean enabled) -{ - GHashTableIter iter; - gpointer widget; - - item->disabled = !enabled; - g_hash_table_iter_init(&iter, item->windows); - while (g_hash_table_iter_next(&iter, &widget, NULL)) - gtk_widget_set_sensitive(GTK_WIDGET(widget), enabled); -} - -void uiMenuItemEnable(uiMenuItem *item) -{ - menuItemEnableDisable(item, TRUE); -} - -void uiMenuItemDisable(uiMenuItem *item) -{ - menuItemEnableDisable(item, FALSE); -} - -void uiMenuItemOnClicked(uiMenuItem *item, void (*f)(uiMenuItem *, uiWindow *, void *), void *data) -{ - if (item->type == typeQuit) - userbug("You cannot call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead."); - item->onClicked = f; - item->onClickedData = data; -} - -int uiMenuItemChecked(uiMenuItem *item) -{ - return item->checked != FALSE; -} - -void uiMenuItemSetChecked(uiMenuItem *item, int checked) -{ - gboolean c; - - // use explicit values - c = FALSE; - if (checked) - c = TRUE; - setChecked(item, c); -} - -static uiMenuItem *newItem(uiMenu *m, int type, const char *name) -{ - uiMenuItem *item; - - if (menusFinalized) - userbug("You cannot create a new menu item after menus have been finalized."); - - item = uiNew(uiMenuItem); - - g_array_append_val(m->items, item); - - item->type = type; - switch (item->type) { - case typeQuit: - item->name = g_strdup("Quit"); - break; - case typePreferences: - item->name = g_strdup("Preferences..."); - break; - case typeAbout: - item->name = g_strdup("About"); - break; - case typeSeparator: - break; - default: - item->name = g_strdup(name); - break; - } - - if (item->type == typeQuit) { - // can't call uiMenuItemOnClicked() here - item->onClicked = onQuitClicked; - item->onClickedData = NULL; - } else - uiMenuItemOnClicked(item, defaultOnClicked, NULL); - - switch (item->type) { - case typeCheckbox: - item->gtype = GTK_TYPE_CHECK_MENU_ITEM; - break; - case typeSeparator: - item->gtype = GTK_TYPE_SEPARATOR_MENU_ITEM; - break; - default: - item->gtype = GTK_TYPE_MENU_ITEM; - break; - } - - item->windows = g_hash_table_new(g_direct_hash, g_direct_equal); - item->popupchild = NULL; - - return item; -} - -uiMenuItem *uiMenuAppendSubmenu(uiMenu *m, uiMenu* child) -{ - uiMenuItem *item; - - if (menusFinalized) - userbug("You cannot create a new menu item after menus have been finalized."); - - item = uiNew(uiMenuItem); - - g_array_append_val(m->items, item); - - item->type = typeSubmenu; - item->name = child->name; - - uiMenuItemOnClicked(item, defaultOnClicked, NULL); - - // checkme - item->gtype = GTK_TYPE_MENU_ITEM; - - item->windows = g_hash_table_new(g_direct_hash, g_direct_equal); - item->popupchild = child; - child->ischild = TRUE; - - return item; -} - -uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) -{ - return newItem(m, typeRegular, name); -} - -uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name) -{ - return newItem(m, typeCheckbox, name); -} - -uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) -{ - if (hasQuit) - userbug("You cannot have multiple Quit menu items in the same program."); - hasQuit = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typeQuit, NULL); -} - -uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) -{ - if (hasPreferences) - userbug("You cannot have multiple Preferences menu items in the same program."); - hasPreferences = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typePreferences, NULL); -} - -uiMenuItem *uiMenuAppendAboutItem(uiMenu *m) -{ - if (hasAbout) - userbug("You cannot have multiple About menu items in the same program."); - hasAbout = TRUE; - newItem(m, typeSeparator, NULL); - return newItem(m, typeAbout, NULL); -} - -void uiMenuAppendSeparator(uiMenu *m) -{ - newItem(m, typeSeparator, NULL); -} - -uiMenu *uiNewMenu(const char *name) -{ - uiMenu *m; - - if (menusFinalized) - userbug("You cannot create a new menu after menus have been finalized."); - if (menus == NULL) - menus = g_array_new(FALSE, TRUE, sizeof (uiMenu *)); - - m = uiNew(uiMenu); - - g_array_append_val(menus, m); - m->id = nmenus; - nmenus++; - - m->name = g_strdup(name); - m->items = g_array_new(FALSE, TRUE, sizeof (uiMenuItem *)); - m->ischild = FALSE; - - return m; -} - -static void appendMenuItem(GtkMenuShell *submenu, uiMenuItem *item, uiWindow *w) -{ - GtkWidget *menuitem; - gulong signal; - struct menuItemWindow *ww; - - menuitem = g_object_new(item->gtype, NULL); - if (item->name != NULL) - gtk_menu_item_set_label(GTK_MENU_ITEM(menuitem), item->name); - if (item->type != typeSeparator) { - signal = g_signal_connect(menuitem, "activate", G_CALLBACK(onClicked), item); - gtk_widget_set_sensitive(menuitem, !item->disabled); - if (item->type == typeCheckbox) - singleSetChecked(GTK_CHECK_MENU_ITEM(menuitem), item->checked, signal); - } - gtk_menu_shell_append(submenu, menuitem); - - ww = uiNew(struct menuItemWindow); - ww->w = w; - ww->signal = signal; - g_hash_table_insert(item->windows, menuitem, ww); - - if (item->popupchild != NULL) - { - int j; - uiMenu* m; - GtkWidget *c_submenu; - - m = item->popupchild; - c_submenu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), c_submenu); - for (j = 0; j < m->items->len; j++) - appendMenuItem(GTK_MENU_SHELL(c_submenu), g_array_index(m->items, uiMenuItem *, j), w); - } -} - -GtkWidget *makeMenubar(uiWindow *w) -{ - GtkWidget *menubar; - guint i, j; - uiMenu *m; - GtkWidget *menuitem; - GtkWidget *submenu; - - menusFinalized = TRUE; - - menubar = gtk_menu_bar_new(); - - if (menus != NULL) - for (i = 0; i < menus->len; i++) { - m = g_array_index(menus, uiMenu *, i); - if (m->ischild) continue; - menuitem = gtk_menu_item_new_with_label(m->name); - submenu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); - for (j = 0; j < m->items->len; j++) - appendMenuItem(GTK_MENU_SHELL(submenu), g_array_index(m->items, uiMenuItem *, j), w); - gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem); - } - - gtk_widget_set_hexpand(menubar, TRUE); - gtk_widget_set_halign(menubar, GTK_ALIGN_FILL); - return menubar; -} - -struct freeMenuItemData { - GArray *items; - guint i; - guint* parent_i; -}; - -static void freeMenu(GtkWidget *widget, gpointer data); - -static void freeMenuItem(GtkWidget *widget, gpointer data) -{ - struct freeMenuItemData *fmi = (struct freeMenuItemData *) data; - uiMenuItem *item; - struct menuItemWindow *w; - - item = g_array_index(fmi->items, uiMenuItem *, fmi->i); - if (item->popupchild != NULL) - freeMenu(widget, fmi->parent_i);//&item->popupchild->id); - w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, widget); - if (g_hash_table_remove(item->windows, widget) == FALSE) - implbug("GtkMenuItem %p not in menu item's item/window map", widget); - uiFree(w); - fmi->i++; -} - -static void freeMenu(GtkWidget *widget, gpointer data) -{ - guint *i = (guint *) data; - uiMenu *m; - GtkMenuItem *item; - GtkWidget *submenu; - struct freeMenuItemData fmi; - - m = g_array_index(menus, uiMenu *, *i); - item = GTK_MENU_ITEM(widget); - submenu = gtk_menu_item_get_submenu(item); - fmi.items = m->items; - fmi.i = 0; - (*i)++; - fmi.parent_i = i; - gtk_container_foreach(GTK_CONTAINER(submenu), freeMenuItem, &fmi); - //(*i)++; -} - -void freeMenubar(GtkWidget *mb) -{ - guint i; - - i = 0; - gtk_container_foreach(GTK_CONTAINER(mb), freeMenu, &i); - // no need to worry about destroying any widgets; destruction of the window they're in will do it for us -} - -void _freeMenu(uiMenu* m) -{ - uiMenuItem *item; - guint j; - - g_free(m->name); - for (j = 0; j < m->items->len; j++) { - item = g_array_index(m->items, uiMenuItem *, j); - if (item->popupchild != NULL) _freeMenu(item->popupchild); - if (g_hash_table_size(item->windows) != 0) - // TODO is this really a userbug()? - implbug("menu item %p (%s) still has uiWindows attached; did you forget to destroy some windows?", item, item->name); - if (item->type != typeSubmenu) g_free(item->name); - g_hash_table_destroy(item->windows); - uiFree(item); - } - g_array_free(m->items, TRUE); - uiFree(m); -} - -void uninitMenus(void) -{ - uiMenu *m; - guint i; - - if (menus == NULL) - return; - for (i = 0; i < menus->len; i++) { - m = g_array_index(menus, uiMenu *, i); - if (m->ischild) continue; - _freeMenu(m); - } - g_array_free(menus, TRUE); -} diff --git a/src/libui_sdl/libui/unix/multilineentry.c b/src/libui_sdl/libui/unix/multilineentry.c deleted file mode 100644 index 09ffd46..0000000 --- a/src/libui_sdl/libui/unix/multilineentry.c +++ /dev/null @@ -1,124 +0,0 @@ -// 6 december 2015 -#include "uipriv_unix.h" - -struct uiMultilineEntry { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *scontainer; - GtkScrolledWindow *sw; - GtkWidget *textviewWidget; - GtkTextView *textview; - GtkTextBuffer *textbuf; - void (*onChanged)(uiMultilineEntry *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiMultilineEntry) - -static void onChanged(GtkTextBuffer *textbuf, gpointer data) -{ - uiMultilineEntry *e = uiMultilineEntry(data); - - (*(e->onChanged))(e, e->onChangedData); -} - -static void defaultOnChanged(uiMultilineEntry *e, void *data) -{ - // do nothing -} - -char *uiMultilineEntryText(uiMultilineEntry *e) -{ - GtkTextIter start, end; - char *tret, *out; - - gtk_text_buffer_get_start_iter(e->textbuf, &start); - gtk_text_buffer_get_end_iter(e->textbuf, &end); - tret = gtk_text_buffer_get_text(e->textbuf, &start, &end, TRUE); - // theoretically we could just return tret because uiUnixStrdupText() is just g_strdup(), but if that ever changes we can't, so let's do it this way to be safe - out = uiUnixStrdupText(tret); - g_free(tret); - return out; -} - -void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) -{ - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(e->textbuf, e->onChangedSignal); - gtk_text_buffer_set_text(e->textbuf, text, -1); - g_signal_handler_unblock(e->textbuf, e->onChangedSignal); -} - -// TODO scroll to end? -void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) -{ - GtkTextIter end; - - gtk_text_buffer_get_end_iter(e->textbuf, &end); - // we need to inhibit sending of ::changed because this WILL send a ::changed otherwise - g_signal_handler_block(e->textbuf, e->onChangedSignal); - gtk_text_buffer_insert(e->textbuf, &end, text, -1); - g_signal_handler_unblock(e->textbuf, e->onChangedSignal); -} - -void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiMultilineEntryReadOnly(uiMultilineEntry *e) -{ - return gtk_text_view_get_editable(e->textview) == FALSE; -} - -void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) -{ - gboolean editable; - - editable = TRUE; - if (readonly) - editable = FALSE; - gtk_text_view_set_editable(e->textview, editable); -} - -static uiMultilineEntry *finishMultilineEntry(GtkPolicyType hpolicy, GtkWrapMode wrapMode) -{ - uiMultilineEntry *e; - - uiUnixNewControl(uiMultilineEntry, e); - - e->widget = gtk_scrolled_window_new(NULL, NULL); - e->scontainer = GTK_CONTAINER(e->widget); - e->sw = GTK_SCROLLED_WINDOW(e->widget); - gtk_scrolled_window_set_policy(e->sw, - hpolicy, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(e->sw, GTK_SHADOW_IN); - - e->textviewWidget = gtk_text_view_new(); - e->textview = GTK_TEXT_VIEW(e->textviewWidget); - gtk_text_view_set_wrap_mode(e->textview, wrapMode); - - gtk_container_add(e->scontainer, e->textviewWidget); - // and make the text view visible; only the scrolled window's visibility is controlled by libui - gtk_widget_show(e->textviewWidget); - - e->textbuf = gtk_text_view_get_buffer(e->textview); - - e->onChangedSignal = g_signal_connect(e->textbuf, "changed", G_CALLBACK(onChanged), e); - uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiMultilineEntry *uiNewMultilineEntry(void) -{ - return finishMultilineEntry(GTK_POLICY_NEVER, GTK_WRAP_WORD); -} - -uiMultilineEntry *uiNewNonWrappingMultilineEntry(void) -{ - return finishMultilineEntry(GTK_POLICY_AUTOMATIC, GTK_WRAP_NONE); -} diff --git a/src/libui_sdl/libui/unix/progressbar.c b/src/libui_sdl/libui/unix/progressbar.c deleted file mode 100644 index 9b543b0..0000000 --- a/src/libui_sdl/libui/unix/progressbar.c +++ /dev/null @@ -1,71 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiProgressBar { - uiUnixControl c; - GtkWidget *widget; - GtkProgressBar *pbar; - gboolean indeterminate; - guint pulser; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiProgressBar) - -static void uiProgressBarDestroy(uiControl *c) -{ - uiProgressBar *p = uiProgressBar(c); - - // be sure to stop the timeout now - if (p->indeterminate) - g_source_remove(p->pulser); - g_object_unref(p->widget); - uiFreeControl(uiControl(p)); -} - -int uiProgressBarValue(uiProgressBar *p) -{ - if (p->indeterminate) - return -1; - return (int) (gtk_progress_bar_get_fraction(p->pbar) * 100); -} - -static gboolean pulse(void* data) -{ - uiProgressBar *p = uiProgressBar(data); - - gtk_progress_bar_pulse(p->pbar); - return TRUE; -} - -void uiProgressBarSetValue(uiProgressBar *p, int value) -{ - if (value == -1) { - if (!p->indeterminate) { - p->indeterminate = TRUE; - // TODO verify the timeout - p->pulser = g_timeout_add(100, pulse, p); - } - return; - } - if (p->indeterminate) { - p->indeterminate = FALSE; - g_source_remove(p->pulser); - } - - if (value < 0 || value > 100) - userbug("Value %d is out of range for a uiProgressBar.", value); - - gtk_progress_bar_set_fraction(p->pbar, ((gdouble) value) / 100); -} - -uiProgressBar *uiNewProgressBar(void) -{ - uiProgressBar *p; - - uiUnixNewControl(uiProgressBar, p); - - p->widget = gtk_progress_bar_new(); - p->pbar = GTK_PROGRESS_BAR(p->widget); - - return p; -} diff --git a/src/libui_sdl/libui/unix/radiobuttons.c b/src/libui_sdl/libui/unix/radiobuttons.c deleted file mode 100644 index da41107..0000000 --- a/src/libui_sdl/libui/unix/radiobuttons.c +++ /dev/null @@ -1,121 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -// on GTK+ a uiRadioButtons is a GtkBox with each of the GtkRadioButtons as children - -struct uiRadioButtons { - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBox *box; - GPtrArray *buttons; - void (*onSelected)(uiRadioButtons *, void *); - void *onSelectedData; - gboolean changing; -}; - -uiUnixControlAllDefaultsExceptDestroy(uiRadioButtons) - -static void defaultOnSelected(uiRadioButtons *r, void *data) -{ - // do nothing -} - -static void onToggled(GtkToggleButton *tb, gpointer data) -{ - uiRadioButtons *r = uiRadioButtons(data); - - // only care if a button is selected - if (!gtk_toggle_button_get_active(tb)) - return; - // ignore programmatic changes - if (r->changing) - return; - (*(r->onSelected))(r, r->onSelectedData); -} - -static void uiRadioButtonsDestroy(uiControl *c) -{ - uiRadioButtons *r = uiRadioButtons(c); - GtkWidget *b; - - while (r->buttons->len != 0) { - b = GTK_WIDGET(g_ptr_array_remove_index(r->buttons, 0)); - gtk_widget_destroy(b); - } - g_ptr_array_free(r->buttons, TRUE); - // and free ourselves - g_object_unref(r->widget); - uiFreeControl(uiControl(r)); -} - -void uiRadioButtonsAppend(uiRadioButtons *r, const char *text) -{ - GtkWidget *rb; - GtkRadioButton *previous; - - previous = NULL; - if (r->buttons->len > 0) - previous = GTK_RADIO_BUTTON(g_ptr_array_index(r->buttons, 0)); - rb = gtk_radio_button_new_with_label_from_widget(previous, text); - g_signal_connect(rb, "toggled", G_CALLBACK(onToggled), r); - gtk_container_add(r->container, rb); - g_ptr_array_add(r->buttons, rb); - gtk_widget_show(rb); -} - -int uiRadioButtonsSelected(uiRadioButtons *r) -{ - GtkToggleButton *tb; - guint i; - - for (i = 0; i < r->buttons->len; i++) { - tb = GTK_TOGGLE_BUTTON(g_ptr_array_index(r->buttons, i)); - if (gtk_toggle_button_get_active(tb)) - return i; - } - return -1; -} - -void uiRadioButtonsSetSelected(uiRadioButtons *r, int n) -{ - GtkToggleButton *tb; - gboolean active; - - active = TRUE; - // TODO this doesn't work - if (n == -1) { - n = uiRadioButtonsSelected(r); - if (n == -1) // no selection; keep it that way - return; - active = FALSE; - } - tb = GTK_TOGGLE_BUTTON(g_ptr_array_index(r->buttons, n)); - // this is easier than remembering all the signals - r->changing = TRUE; - gtk_toggle_button_set_active(tb, active); - r->changing = FALSE; -} - -void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data) -{ - r->onSelected = f; - r->onSelectedData = data; -} - -uiRadioButtons *uiNewRadioButtons(void) -{ - uiRadioButtons *r; - - uiUnixNewControl(uiRadioButtons, r); - - r->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - r->container = GTK_CONTAINER(r->widget); - r->box = GTK_BOX(r->widget); - - r->buttons = g_ptr_array_new(); - - uiRadioButtonsOnSelected(r, defaultOnSelected, NULL); - - return r; -} diff --git a/src/libui_sdl/libui/unix/separator.c b/src/libui_sdl/libui/unix/separator.c deleted file mode 100644 index 02c75da..0000000 --- a/src/libui_sdl/libui/unix/separator.c +++ /dev/null @@ -1,34 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiSeparator { - uiUnixControl c; - GtkWidget *widget; - GtkSeparator *separator; -}; - -uiUnixControlAllDefaults(uiSeparator) - -uiSeparator *uiNewHorizontalSeparator(void) -{ - uiSeparator *s; - - uiUnixNewControl(uiSeparator, s); - - s->widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - s->separator = GTK_SEPARATOR(s->widget); - - return s; -} - -uiSeparator *uiNewVerticalSeparator(void) -{ - uiSeparator *s; - - uiUnixNewControl(uiSeparator, s); - - s->widget = gtk_separator_new(GTK_ORIENTATION_VERTICAL); - s->separator = GTK_SEPARATOR(s->widget); - - return s; -} diff --git a/src/libui_sdl/libui/unix/slider.c b/src/libui_sdl/libui/unix/slider.c deleted file mode 100644 index 7f0cc24..0000000 --- a/src/libui_sdl/libui/unix/slider.c +++ /dev/null @@ -1,71 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiSlider { - uiUnixControl c; - GtkWidget *widget; - GtkRange *range; - GtkScale *scale; - void (*onChanged)(uiSlider *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiSlider) - -static void onChanged(GtkRange *range, gpointer data) -{ - uiSlider *s = uiSlider(data); - - (*(s->onChanged))(s, s->onChangedData); -} - -static void defaultOnChanged(uiSlider *s, void *data) -{ - // do nothing -} - -int uiSliderValue(uiSlider *s) -{ - return gtk_range_get_value(s->range); -} - -void uiSliderSetValue(uiSlider *s, int value) -{ - // we need to inhibit sending of ::value-changed because this WILL send a ::value-changed otherwise - g_signal_handler_block(s->range, s->onChangedSignal); - gtk_range_set_value(s->range, value); - g_signal_handler_unblock(s->range, s->onChangedSignal); -} - -void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -uiSlider *uiNewSlider(int min, int max) -{ - uiSlider *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiUnixNewControl(uiSlider, s); - - s->widget = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, min, max, 1); - s->range = GTK_RANGE(s->widget); - s->scale = GTK_SCALE(s->widget); - - // ensure integers, just to be safe - gtk_scale_set_digits(s->scale, 0); - - s->onChangedSignal = g_signal_connect(s->scale, "value-changed", G_CALLBACK(onChanged), s); - uiSliderOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/src/libui_sdl/libui/unix/spinbox.c b/src/libui_sdl/libui/unix/spinbox.c deleted file mode 100644 index 90a5d3c..0000000 --- a/src/libui_sdl/libui/unix/spinbox.c +++ /dev/null @@ -1,72 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiSpinbox { - uiUnixControl c; - GtkWidget *widget; - GtkEntry *entry; - GtkSpinButton *spinButton; - void (*onChanged)(uiSpinbox *, void *); - void *onChangedData; - gulong onChangedSignal; -}; - -uiUnixControlAllDefaults(uiSpinbox) - -static void onChanged(GtkSpinButton *sb, gpointer data) -{ - uiSpinbox *s = uiSpinbox(data); - - (*(s->onChanged))(s, s->onChangedData); -} - -static void defaultOnChanged(uiSpinbox *s, void *data) -{ - // do nothing -} - -int uiSpinboxValue(uiSpinbox *s) -{ - return gtk_spin_button_get_value(s->spinButton); -} - -void uiSpinboxSetValue(uiSpinbox *s, int value) -{ - // we need to inhibit sending of ::value-changed because this WILL send a ::value-changed otherwise - g_signal_handler_block(s->spinButton, s->onChangedSignal); - // this clamps for us - gtk_spin_button_set_value(s->spinButton, (gdouble) value); - g_signal_handler_unblock(s->spinButton, s->onChangedSignal); -} - -void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -uiSpinbox *uiNewSpinbox(int min, int max) -{ - uiSpinbox *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiUnixNewControl(uiSpinbox, s); - - s->widget = gtk_spin_button_new_with_range(min, max, 1); - s->entry = GTK_ENTRY(s->widget); - s->spinButton = GTK_SPIN_BUTTON(s->widget); - - // ensure integers, just to be safe - gtk_spin_button_set_digits(s->spinButton, 0); - - s->onChangedSignal = g_signal_connect(s->spinButton, "value-changed", G_CALLBACK(onChanged), s); - uiSpinboxOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/src/libui_sdl/libui/unix/stddialogs.c b/src/libui_sdl/libui/unix/stddialogs.c deleted file mode 100644 index 3daeffa..0000000 --- a/src/libui_sdl/libui/unix/stddialogs.c +++ /dev/null @@ -1,116 +0,0 @@ -// 26 june 2015 -#include "uipriv_unix.h" - -// LONGTERM figure out why, and describe, that this is the desired behavior -// LONGTERM also point out that font and color buttons also work like this - -#define windowWindow(w) ((w)?(GTK_WINDOW(uiControlHandle(uiControl(w)))):NULL) - -static char *filedialog(GtkWindow *parent, GtkFileChooserAction mode, const gchar *confirm, const char* filter, const char* initpath) -{ - GtkWidget *fcd; - GtkFileChooser *fc; - gint response; - char *filename; - - fcd = gtk_file_chooser_dialog_new(NULL, parent, mode, - "_Cancel", GTK_RESPONSE_CANCEL, - confirm, GTK_RESPONSE_ACCEPT, - NULL); - fc = GTK_FILE_CHOOSER(fcd); - - // filters - { - gchar _filter[256]; - gchar* fp = &_filter[0]; int s = 0; - gchar* fname; - for (int i = 0; i < 255; i++) - { - if (filter[i] == '|' || filter[i] == '\0') - { - _filter[i] = '\0'; - if (s & 1) - { - GtkFileFilter* filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, fname); - - for (gchar* j = fp; ; j++) - { - if (*j == ';') - { - *j = '\0'; - gtk_file_filter_add_pattern(filter, fp); - fp = j+1; - } - else if (*j == '\0') - { - gtk_file_filter_add_pattern(filter, fp); - break; - } - } - - gtk_file_chooser_add_filter(fc, filter); - } - else - { - fname = fp; - } - fp = &_filter[i+1]; - s++; - if (s >= 8) break; - if (filter[i] == '\0') break; - } - else - _filter[i] = filter[i]; - } - } - - gtk_file_chooser_set_local_only(fc, FALSE); - gtk_file_chooser_set_select_multiple(fc, FALSE); - gtk_file_chooser_set_show_hidden(fc, TRUE); - gtk_file_chooser_set_do_overwrite_confirmation(fc, TRUE); - gtk_file_chooser_set_create_folders(fc, TRUE); - if (initpath && strlen(initpath)>0) - gtk_file_chooser_set_current_folder(fc, initpath); - - response = gtk_dialog_run(GTK_DIALOG(fcd)); - if (response != GTK_RESPONSE_ACCEPT) { - gtk_widget_destroy(fcd); - return NULL; - } - filename = uiUnixStrdupText(gtk_file_chooser_get_filename(fc)); - gtk_widget_destroy(fcd); - return filename; -} - -char *uiOpenFile(uiWindow *parent, const char* filter, const char* initpath) -{ - return filedialog(windowWindow(parent), GTK_FILE_CHOOSER_ACTION_OPEN, "_Open", filter, initpath); -} - -char *uiSaveFile(uiWindow *parent, const char* filter, const char* initpath) -{ - return filedialog(windowWindow(parent), GTK_FILE_CHOOSER_ACTION_SAVE, "_Save", filter, initpath); -} - -static void msgbox(GtkWindow *parent, const char *title, const char *description, GtkMessageType type, GtkButtonsType buttons) -{ - GtkWidget *md; - - md = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL, - type, buttons, - "%s", title); - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(md), "%s", description); - gtk_dialog_run(GTK_DIALOG(md)); - gtk_widget_destroy(md); -} - -void uiMsgBox(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, GTK_MESSAGE_OTHER, GTK_BUTTONS_OK); -} - -void uiMsgBoxError(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK); -} diff --git a/src/libui_sdl/libui/unix/tab.c b/src/libui_sdl/libui/unix/tab.c deleted file mode 100644 index 552e0e3..0000000 --- a/src/libui_sdl/libui/unix/tab.c +++ /dev/null @@ -1,97 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiTab { - uiUnixControl c; - - GtkWidget *widget; - GtkContainer *container; - GtkNotebook *notebook; - - GArray *pages; // []*struct child -}; - -uiUnixControlAllDefaultsExceptDestroy(uiTab) - -static void uiTabDestroy(uiControl *c) -{ - uiTab *t = uiTab(c); - guint i; - struct child *page; - - for (i = 0; i < t->pages->len; i++) { - page = g_array_index(t->pages, struct child *, i); - childDestroy(page); - } - g_array_free(t->pages, TRUE); - // and free ourselves - g_object_unref(t->widget); - uiFreeControl(uiControl(t)); -} - -void uiTabAppend(uiTab *t, const char *name, uiControl *child) -{ - uiTabInsertAt(t, name, t->pages->len, child); -} - -void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) -{ - struct child *page; - - // this will create a tab, because of gtk_container_add() - page = newChildWithBox(child, uiControl(t), t->container, 0); - - gtk_notebook_set_tab_label_text(t->notebook, childBox(page), name); - gtk_notebook_reorder_child(t->notebook, childBox(page), n); - - g_array_insert_val(t->pages, n, page); -} - -void uiTabDelete(uiTab *t, int n) -{ - struct child *page; - - page = g_array_index(t->pages, struct child *, n); - // this will remove the tab, because gtk_widget_destroy() calls gtk_container_remove() - childRemove(page); - g_array_remove_index(t->pages, n); -} - -int uiTabNumPages(uiTab *t) -{ - return t->pages->len; -} - -int uiTabMargined(uiTab *t, int n) -{ - struct child *page; - - page = g_array_index(t->pages, struct child *, n); - return childFlag(page); -} - -void uiTabSetMargined(uiTab *t, int n, int margined) -{ - struct child *page; - - page = g_array_index(t->pages, struct child *, n); - childSetFlag(page, margined); - childSetMargined(page, childFlag(page)); -} - -uiTab *uiNewTab(void) -{ - uiTab *t; - - uiUnixNewControl(uiTab, t); - - t->widget = gtk_notebook_new(); - t->container = GTK_CONTAINER(t->widget); - t->notebook = GTK_NOTEBOOK(t->widget); - - gtk_notebook_set_scrollable(t->notebook, TRUE); - - t->pages = g_array_new(FALSE, TRUE, sizeof (struct child *)); - - return t; -} diff --git a/src/libui_sdl/libui/unix/text.c b/src/libui_sdl/libui/unix/text.c deleted file mode 100644 index ad92738..0000000 --- a/src/libui_sdl/libui/unix/text.c +++ /dev/null @@ -1,12 +0,0 @@ -// 9 april 2015 -#include "uipriv_unix.h" - -char *uiUnixStrdupText(const char *t) -{ - return g_strdup(t); -} - -void uiFreeText(char *t) -{ - g_free(t); -} diff --git a/src/libui_sdl/libui/unix/uipriv_unix.h b/src/libui_sdl/libui/unix/uipriv_unix.h deleted file mode 100644 index 9b77188..0000000 --- a/src/libui_sdl/libui/unix/uipriv_unix.h +++ /dev/null @@ -1,71 +0,0 @@ -// 22 april 2015 -#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40 -#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40 -#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10 -#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10 -#include <gtk/gtk.h> -#include <math.h> -#include <dlfcn.h> // see drawtext.c, gl.c -#include <langinfo.h> -#include <string.h> -#include <stdlib.h> -#include "../ui.h" -#include "../ui_unix.h" -#include "../common/uipriv.h" - -#define gtkXMargin 12 -#define gtkYMargin 12 -#define gtkXPadding 12 -#define gtkYPadding 6 - -// menu.c -extern GtkWidget *makeMenubar(uiWindow *); -extern void freeMenubar(GtkWidget *); -extern void uninitMenus(void); - -// alloc.c -extern void initAlloc(void); -extern void uninitAlloc(void); - -// util.c -extern void setMargined(GtkContainer *, int); - -// child.c -extern struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer); -extern struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined); -extern void childRemove(struct child *c); -extern void childDestroy(struct child *c); -extern GtkWidget *childWidget(struct child *c); -extern int childFlag(struct child *c); -extern void childSetFlag(struct child *c, int flag); -extern GtkWidget *childBox(struct child *c); -extern void childSetMargined(struct child *c, int margined); - -// draw.c -extern uiDrawContext *newContext(cairo_t *); -extern void freeContext(uiDrawContext *); - -// drawtext.c -extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add); -extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc); - -// graphemes.c -extern ptrdiff_t *graphemes(const char *text, PangoContext *context); - -// image.c -/*TODO remove this*/typedef struct uiImage uiImage; -extern cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w); - -// cellrendererbutton.c -extern GtkCellRenderer *newCellRendererButton(void); - -// future.c -extern void loadFutures(void); -extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha); -extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name); - -// gl.c -extern uiGLContext *createGLContext(GtkWidget* widget, int maj, int min); -extern void freeGLContext(uiGLContext* glctx); -extern void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx); - diff --git a/src/libui_sdl/libui/unix/util.c b/src/libui_sdl/libui/unix/util.c deleted file mode 100644 index 7f4f43f..0000000 --- a/src/libui_sdl/libui/unix/util.c +++ /dev/null @@ -1,10 +0,0 @@ -// 18 april 2015 -#include "uipriv_unix.h" - -void setMargined(GtkContainer *c, int margined) -{ - if (margined) - gtk_container_set_border_width(c, gtkXMargin); - else - gtk_container_set_border_width(c, 0); -} diff --git a/src/libui_sdl/libui/unix/window.c b/src/libui_sdl/libui/unix/window.c deleted file mode 100644 index 6d5e2de..0000000 --- a/src/libui_sdl/libui/unix/window.c +++ /dev/null @@ -1,462 +0,0 @@ -// 11 june 2015 -#include "uipriv_unix.h" - -struct uiWindow { - uiUnixControl c; - - GtkWidget *widget; - GtkContainer *container; - GtkWindow *window; - - GtkWidget *vboxWidget; - GtkContainer *vboxContainer; - GtkBox *vbox; - - GtkWidget *childHolderWidget; - GtkContainer *childHolderContainer; - - GtkWidget *menubar; - - uiControl *child; - int margined; - - int width, height; - - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - void (*onContentSizeChanged)(uiWindow *, void *); - void *onContentSizeChangedData; - void (*onDropFile)(uiWindow *, char *, void *); - void *onDropFileData; - void (*onGetFocus)(uiWindow *, void *); - void *onGetFocusData; - void (*onLoseFocus)(uiWindow *, void *); - void *onLoseFocusData; - - gboolean fullscreen; -}; - -static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) -{ - uiWindow *w = uiWindow(data); - - // manually destroy the window ourselves; don't let the delete-event handler do it - if ((*(w->onClosing))(w, w->onClosingData)) - uiControlDestroy(uiControl(w)); - // don't continue to the default delete-event handler; we destroyed the window by now - return TRUE; -} - -static void onSizeAllocate(GtkWidget *widget, GdkRectangle *allocation, gpointer data) -{ - uiWindow *w = uiWindow(data); - - // TODO deal with spurious size-allocates - (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); -} - -static gboolean onGetFocus(GtkWidget *win, GdkEvent *e, gpointer data) -{ - uiWindow *w = uiWindow(data); - if (w->onGetFocus) - w->onGetFocus(w, w->onGetFocusData); -} - -static gboolean onLoseFocus(GtkWidget *win, GdkEvent *e, gpointer data) -{ - uiWindow *w = uiWindow(data); - if (w->onLoseFocus) - w->onLoseFocus(w, w->onLoseFocusData); -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 0; -} - -static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) -{ - // do nothing -} - -static void uiWindowDestroy(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // first hide ourselves - gtk_widget_hide(w->widget); - // now destroy the child - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); - uiControlDestroy(w->child); - } - // now destroy the menus, if any - if (w->menubar != NULL) - freeMenubar(w->menubar); - gtk_widget_destroy(w->childHolderWidget); - gtk_widget_destroy(w->vboxWidget); - // and finally free ourselves - // use gtk_widget_destroy() instead of g_object_unref() because GTK+ has internal references (see #165) - gtk_widget_destroy(w->widget); - uiFreeControl(uiControl(w)); -} - -void uiWindowSetPosition(uiWindow *w, int x, int y) -{ - if (!w) return; - - gtk_window_move(w->window, x, y); -} - -void uiWindowPosition(uiWindow *w, int *x, int *y) -{ - if (!w) return; - - int xx, yy; - gtk_window_get_position(w->window, &xx, &yy); - if (x) *x = xx; - if (y) *y = yy; -} - -uiUnixControlDefaultHandle(uiWindow) - -uiControl *uiWindowParent(uiControl *c) -{ - return NULL; -} - -void uiWindowSetParent(uiControl *c, uiControl *parent) -{ - uiUserBugCannotSetParentOnToplevel("uiWindow"); -} - -static int uiWindowToplevel(uiControl *c) -{ - return 1; -} - -uiUnixControlDefaultVisible(uiWindow) - -static void uiWindowShow(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // don't use gtk_widget_show_all() as that will show all children, regardless of user settings - // don't use gtk_widget_show(); that doesn't bring to front or give keyboard focus - // (gtk_window_present() does call gtk_widget_show() though) - gtk_window_present(w->window); - - // set the size properly - int width = w->width; - int height = w->height; - if (w->menubar) - { - GtkRequisition min, nat; - int menuheight; - gtk_widget_get_preferred_size(w->menubar, &min, &nat); - menuheight = min.height; - if (nat.height > menuheight) menuheight = nat.height; - height += menuheight; - } - gtk_window_resize(w->window, width, height); -} - -static void uiWindowSetFocus(uiControl* c) -{ - gtk_window_present(GTK_WINDOW(uiWindow(c)->widget)); -} - -uiUnixControlDefaultHide(uiWindow) -uiUnixControlDefaultEnabled(uiWindow) -uiUnixControlDefaultEnable(uiWindow) -uiUnixControlDefaultDisable(uiWindow) -//uiUnixControlDefaultSetFocus(uiWindow) -uiUnixControlDefaultSetMinSize(uiWindow) -// TODO? -uiUnixControlDefaultSetContainer(uiWindow) - -char *uiWindowTitle(uiWindow *w) -{ - return uiUnixStrdupText(gtk_window_get_title(w->window)); -} - -void uiWindowSetTitle(uiWindow *w, const char *title) -{ - gtk_window_set_title(w->window, title); -} - -void uiWindowContentSize(uiWindow *w, int *width, int *height) -{ - GtkAllocation allocation; - - gtk_widget_get_allocation(w->childHolderWidget, &allocation); - *width = allocation.width; - *height = allocation.height; -} - -void uiWindowSetContentSize(uiWindow *w, int width, int height) -{ - GtkAllocation childAlloc; - gint winWidth, winHeight; - - // we need to resize the child holder widget to the given size - // we can't resize that without running the event loop - // but we can do gtk_window_set_size() - // so how do we deal with the differences in sizes? - // simple arithmetic, of course! - - // from what I can tell, the return from gtk_widget_get_allocation(w->window) and gtk_window_get_size(w->window) will be the same - // this is not affected by Wayland and not affected by GTK+ builtin CSD - // so we can safely juse use them to get the real window size! - // since we're using gtk_window_resize(), use the latter - gtk_window_get_size(w->window, &winWidth, &winHeight); - - // now get the child holder widget's current allocation - gtk_widget_get_allocation(w->childHolderWidget, &childAlloc); - // and punch that out of the window size - winWidth -= childAlloc.width; - winHeight -= childAlloc.height; - - // now we just need to add the new size back in - winWidth += width; - winHeight += height; - // and set it - // this will not move the window in my tests, so we're good - gtk_window_resize(w->window, winWidth, winHeight); -} - -int uiWindowMinimized(uiWindow *w) -{ - // TODO!! - return 0; -} - -void uiWindowSetMinimized(uiWindow *w, int minimized) -{ - if (minimized) - gtk_window_iconify(w->window); - else - gtk_window_deiconify(w->window); -} - -int uiWindowMaximized(uiWindow *w) -{ - return gtk_window_is_maximized(w->window); -} - -void uiWindowSetMaximized(uiWindow *w, int maximized) -{ - if (maximized) - gtk_window_maximize(w->window); - else - gtk_window_unmaximize(w->window); -} - - -int uiWindowFullscreen(uiWindow *w) -{ - return w->fullscreen; -} - -// TODO use window-state-event to track -// TODO does this send an extra size changed? -// TODO what behavior do we want? -void uiWindowSetFullscreen(uiWindow *w, int fullscreen) -{ - w->fullscreen = fullscreen; - if (w->fullscreen) - gtk_window_fullscreen(w->window); - else - gtk_window_unfullscreen(w->window); -} - -void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onContentSizeChanged = f; - w->onContentSizeChangedData = data; -} - -void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) -{ - w->onClosing = f; - w->onClosingData = data; -} - -void uiWindowOnDropFile(uiWindow *w, void (*f)(uiWindow *, char *, void *), void *data) -{ - w->onDropFile = f; - w->onDropFileData = data; -} - -void uiWindowOnGetFocus(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onGetFocus = f; - w->onGetFocusData = data; -} - -void uiWindowOnLoseFocus(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onLoseFocus = f; - w->onLoseFocusData = data; -} - -int uiWindowBorderless(uiWindow *w) -{ - return gtk_window_get_decorated(w->window) == FALSE; -} - -void uiWindowSetBorderless(uiWindow *w, int borderless) -{ - gtk_window_set_decorated(w->window, borderless == 0); -} - -// TODO save and restore expands and aligns -void uiWindowSetChild(uiWindow *w, uiControl *child) -{ - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); - } - w->child = child; - if (w->child != NULL) { - uiControlSetParent(w->child, uiControl(w)); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, FALSE); - } -} - -int uiWindowMargined(uiWindow *w) -{ - return w->margined; -} - -void uiWindowSetMargined(uiWindow *w, int margined) -{ - w->margined = margined; - setMargined(w->childHolderContainer, w->margined); -} - -static void onDragDataReceived(GtkWidget* widget, GdkDragContext* ctx, gint x, gint y, GtkSelectionData* data, guint info, guint time, gpointer userdata) -{ - uiWindow* w = (uiWindow*)userdata; - - if (gtk_selection_data_get_length(data) > 0 && gtk_selection_data_get_format(data) == 8) - { - gchar** files = gtk_selection_data_get_uris(data); - if (files != NULL && files[0] != NULL) - { - // TODO: multi file support? - - gboolean success = FALSE; - - gchar* file = g_filename_from_uri(files[0], NULL, NULL); - if (file) - { - if (w->onDropFile) - w->onDropFile(w, file, w->onDropFileData); - - success = TRUE; - g_free(file); - } - - - g_strfreev(files); - gtk_drag_finish(ctx, success, FALSE, time); - return; - } - - if (files != NULL) g_strfreev(files); - gtk_drag_finish(ctx, FALSE, FALSE, time); - } -} - -void uiWindowSetDropTarget(uiWindow* w, int drop) -{ - if (!drop) - { - gtk_drag_dest_unset(w->widget); - return; - } - - GtkTargetEntry entry; - entry.target = "text/uri-list"; - entry.flags = GTK_TARGET_OTHER_APP; - entry.info = 1; - - // CHECKME: action copy? - gtk_drag_dest_set(w->widget, GTK_DEST_DEFAULT_ALL, &entry, 1, GDK_ACTION_COPY|GDK_ACTION_MOVE); - - g_signal_connect(w->widget, "drag-data-received", G_CALLBACK(onDragDataReceived), w); -} - -uiWindow *uiNewWindow(const char *title, int width, int height, int maximized, int hasMenubar, int resizable) -{ - uiWindow *w; - - if (!resizable) maximized = 0; - - uiUnixNewControl(uiWindow, w); - - w->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); - w->container = GTK_CONTAINER(w->widget); - w->window = GTK_WINDOW(w->widget); - - gtk_window_set_title(w->window, title); - gtk_window_resize(w->window, width, height); - - w->vboxWidget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - w->vboxContainer = GTK_CONTAINER(w->vboxWidget); - w->vbox = GTK_BOX(w->vboxWidget); - - // set the vbox as the GtkWindow child - gtk_container_add(w->container, w->vboxWidget); - - if (hasMenubar) { - w->menubar = makeMenubar(uiWindow(w)); - gtk_container_add(w->vboxContainer, w->menubar); - } - else - w->menubar = NULL; - - w->childHolderWidget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - w->childHolderContainer = GTK_CONTAINER(w->childHolderWidget); - gtk_widget_set_hexpand(w->childHolderWidget, TRUE); - gtk_widget_set_halign(w->childHolderWidget, GTK_ALIGN_FILL); - gtk_widget_set_vexpand(w->childHolderWidget, TRUE); - gtk_widget_set_valign(w->childHolderWidget, GTK_ALIGN_FILL); - gtk_box_set_homogeneous(GTK_BOX(w->childHolderWidget), TRUE); - gtk_container_add(w->vboxContainer, w->childHolderWidget); - - // show everything in the vbox, but not the GtkWindow itself - gtk_widget_show_all(w->vboxWidget); - - // and connect our events - g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w); - g_signal_connect(w->childHolderWidget, "size-allocate", G_CALLBACK(onSizeAllocate), w); - g_signal_connect(w->widget, "focus-in-event", G_CALLBACK(onGetFocus), w); - g_signal_connect(w->widget, "focus-out-event", G_CALLBACK(onLoseFocus), w); - - uiWindowOnClosing(w, defaultOnClosing, NULL); - uiWindowOnContentSizeChanged(w, defaultOnPositionContentSizeChanged, NULL); - - uiWindowOnDropFile(w, NULL, NULL); - uiWindowOnGetFocus(w, NULL, NULL); - uiWindowOnLoseFocus(w, NULL, NULL); - - // normally it's SetParent() that does this, but we can't call SetParent() on a uiWindow - // TODO we really need to clean this up, especially since see uiWindowDestroy() above - g_object_ref(w->widget); - - gtk_window_set_resizable(w->window, resizable?TRUE:FALSE); - - w->width = width; - w->height = height; - - if (maximized) - gtk_window_maximize(w->window); - else - gtk_window_set_position(w->window, GTK_WIN_POS_CENTER); - - return w; -} - |