Added uiMultilineEntry, wrote it on GTK+, and wrote the uiQueueMain() test. It works on Unix.

This commit is contained in:
Pietro Gagliardi 2015-12-06 01:18:32 -05:00
parent 3394142357
commit 2705f93305
4 changed files with 222 additions and 0 deletions

89
test/queuemaintest.cpp Normal file
View File

@ -0,0 +1,89 @@
// 6 december 2015
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "../ui.h"
using namespace std;
uiMultilineEntry *e;
condition_variable cv;
mutex m;
unique_lock<mutex> ourlock(m);
thread *timeThread;
void sayTime(void *data)
{
char *s = (char *) data;
uiMultilineEntryAppend(e, s);
delete s;
}
void threadproc(void)
{
while (cv.wait_for(ourlock, chrono::seconds(1)) == cv_status::timeout) {
time_t t;
char *base;
char *s;
t = time(NULL);
base = ctime(&t);
s = new char[strlen(base) + 1];
strcpy(s, base);
uiQueueMain(sayTime, s);
}
}
int onClosing(uiWindow *w, void *data)
{
cv.notify_all();
// C++ throws a hissy fit if you don't do this
// we might as well, to ensure no uiQueueMain() gets in after uiQuit()
timeThread->join();
uiQuit();
return 1;
}
void saySomething(uiButton *b, void *data)
{
uiMultilineEntryAppend(e, "Saying something\n");
}
int main(void)
{
uiInitOptions o;
uiWindow *w;
uiBox *b;
uiButton *btn;
memset(&o, 0, sizeof (uiInitOptions));
if (uiInit(&o) != NULL)
abort();
w = uiNewWindow("Hello", 320, 240, 0);
uiWindowSetMargined(w, 1);
b = uiNewVerticalBox();
uiBoxSetPadded(b, 1);
uiWindowSetChild(w, uiControl(b));
e = uiNewMultilineEntry();
uiMultilineEntrySetReadOnly(e, 1);
btn = uiNewButton("Say Something");
uiButtonOnClicked(btn, saySomething, NULL);
uiBoxAppend(b, uiControl(btn), 0);
uiBoxAppend(b, uiControl(e), 1);
timeThread = new thread(threadproc);
uiWindowOnClosing(w, onClosing, NULL);
uiControlShow(uiControl(w));
uiMain();
return 0;
}

15
ui.h
View File

@ -229,6 +229,21 @@ _UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);
_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void); _UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);
_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void); _UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);
// TODO merge with uiEntry? some things can't be shared (for instance, the future Invalid()
// TODO how are line endings converted?
// TODO provide a facility for allowing horizontal scrolling
// TODO provide a facility for entering tab stops?
typedef struct uiMultilineEntry uiMultilineEntry;
_UI_EXTERN uintmax_t uiMultilineEntryType(void);
#define uiMultilineEntry(this) ((uiMultilineEntry *) uiIsA((this), uiMultilineEntryType(), 1))
_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e);
_UI_EXTERN void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text);
_UI_EXTERN void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text);
_UI_EXTERN void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data);
_UI_EXTERN int uiMultilineEntryReadOnly(uiMultilineEntry *e);
_UI_EXTERN void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly);
_UI_EXTERN uiMultilineEntry *uiNewMultilineEntry(void);
typedef struct uiMenu uiMenu; typedef struct uiMenu uiMenu;
typedef struct uiMenuItem uiMenuItem; typedef struct uiMenuItem uiMenuItem;
_UI_EXTERN uintmax_t uiMenuType(void); _UI_EXTERN uintmax_t uiMenuType(void);

View File

@ -16,6 +16,7 @@ CFILES += \
unix/label.c \ unix/label.c \
unix/main.c \ unix/main.c \
unix/menu.c \ unix/menu.c \
unix/multilineentry.c \
unix/progressbar.c \ unix/progressbar.c \
unix/radiobuttons.c \ unix/radiobuttons.c \
unix/separator.c \ unix/separator.c \

117
unix/multilineentry.c Normal file
View File

@ -0,0 +1,117 @@
// 6 december 2015
#include "uipriv_unix.h"
// TODO: ensure this can only be used to enter plain text
struct uiMultilineEntry {
uiUnixControl c;
GtkWidget *widget;
GtkContainer *scontainer;
GtkScrolledWindow *sw;
GtkWidget *textviewWidget;
GtkTextView *textview;
GtkTextBuffer *textbuf;
void (*onChanged)(uiMultilineEntry *, void *);
void *onChangedData;
gulong onChangedSignal;
};
uiUnixDefineControl(
uiMultilineEntry, // type name
uiMultilineEntryType // type function
)
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)
{
// TODO does this send a changed signal?
gtk_text_buffer_set_text(e->textbuf, text, -1);
}
// TODO scroll to end?
void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text)
{
GtkTextIter end;
gtk_text_buffer_get_end_iter(e->textbuf, &end);
// TODO does this send a changed signal?
gtk_text_buffer_insert(e->textbuf, &end, text, -1);
}
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);
}
uiMultilineEntry *uiNewMultilineEntry(void)
{
uiMultilineEntry *e;
e = (uiMultilineEntry *) uiNewControl(uiMultilineEntryType());
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,
GTK_POLICY_NEVER,
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, GTK_WRAP_WORD);
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);
uiUnixFinishNewControl(e, uiMultilineEntry);
return e;
}