Merge pull request #297 from cody271/datetime
Improve uiDateTimePicker by adding functions to set and get the displayed date. Updates #309
This commit is contained in:
commit
d02784838e
|
@ -4,10 +4,113 @@
|
|||
struct uiDateTimePicker {
|
||||
uiDarwinControl c;
|
||||
NSDatePicker *dp;
|
||||
void (*onChanged)(uiDateTimePicker *, void *);
|
||||
void *onChangedData;
|
||||
};
|
||||
|
||||
@interface uiprivDatePickerDelegateClass : NSObject <NSDatePickerCellDelegate> {
|
||||
struct uiprivMap *pickers;
|
||||
}
|
||||
- (void)datePickerCell:(NSDatePickerCell *)aDatePickerCell validateProposedDateValue:(NSDate **)proposedDateValue timeInterval:(NSTimeInterval *)proposedTimeInterval;
|
||||
- (void)doTimer:(NSTimer *)timer;
|
||||
- (void)registerPicker:(uiDateTimePicker *)b;
|
||||
- (void)unregisterPicker:(uiDateTimePicker *)b;
|
||||
@end
|
||||
|
||||
@implementation uiprivDatePickerDelegateClass
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
self->pickers = uiprivNewMap();
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
uiprivMapDestroy(self->pickers);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)datePickerCell:(NSDatePickerCell *)aDatePickerCell
|
||||
validateProposedDateValue:(NSDate **)proposedDateValue
|
||||
timeInterval:(NSTimeInterval *)proposedTimeInterval
|
||||
{
|
||||
uiDateTimePicker *d;
|
||||
|
||||
d = (uiDateTimePicker *) uiprivMapGet(self->pickers, aDatePickerCell);
|
||||
[NSTimer scheduledTimerWithTimeInterval:0
|
||||
target:self
|
||||
selector:@selector(doTimer:)
|
||||
userInfo:[NSValue valueWithPointer:d]
|
||||
repeats:NO];
|
||||
}
|
||||
|
||||
- (void)doTimer:(NSTimer *)timer
|
||||
{
|
||||
uiDateTimePicker *d;
|
||||
|
||||
d = (uiDateTimePicker *) [((NSValue *)[timer userInfo]) pointerValue];
|
||||
(*(d->onChanged))(d, d->onChangedData);
|
||||
}
|
||||
|
||||
- (void)registerPicker:(uiDateTimePicker *)d
|
||||
{
|
||||
uiprivMapSet(self->pickers, d->dp.cell, d);
|
||||
[d->dp setDelegate:self];
|
||||
}
|
||||
|
||||
- (void)unregisterPicker:(uiDateTimePicker *)d
|
||||
{
|
||||
[d->dp setDelegate:nil];
|
||||
uiprivMapDelete(self->pickers, d->dp.cell);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static uiprivDatePickerDelegateClass *datePickerDelegate = nil;
|
||||
|
||||
uiDarwinControlAllDefaults(uiDateTimePicker, dp)
|
||||
|
||||
static void defaultOnChanged(uiDateTimePicker *d, void *data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tmbuf;
|
||||
NSDate *date;
|
||||
|
||||
date = [d->dp dateValue];
|
||||
t = (time_t) [date timeIntervalSince1970];
|
||||
|
||||
// Copy time to minimize a race condition
|
||||
// time.h functions use global non-thread-safe data
|
||||
tmbuf = *localtime(&t);
|
||||
memcpy(time, &tmbuf, sizeof(struct tm));
|
||||
}
|
||||
|
||||
void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tmbuf;
|
||||
|
||||
// Copy time because mktime() modifies its argument
|
||||
memcpy(&tmbuf, time, sizeof(struct tm));
|
||||
t = mktime(&tmbuf);
|
||||
|
||||
[d->dp setDateValue:[NSDate dateWithTimeIntervalSince1970:t]];
|
||||
}
|
||||
|
||||
void uiDateTimePickerOnChanged(uiDateTimePicker *d, void (*f)(uiDateTimePicker *, void *), void *data)
|
||||
{
|
||||
d->onChanged = f;
|
||||
d->onChangedData = data;
|
||||
}
|
||||
|
||||
static uiDateTimePicker *finishNewDateTimePicker(NSDatePickerElementFlags elements)
|
||||
{
|
||||
uiDateTimePicker *d;
|
||||
|
@ -15,6 +118,7 @@ static uiDateTimePicker *finishNewDateTimePicker(NSDatePickerElementFlags elemen
|
|||
uiDarwinNewControl(uiDateTimePicker, d);
|
||||
|
||||
d->dp = [[NSDatePicker alloc] initWithFrame:NSZeroRect];
|
||||
[d->dp setDateValue:[NSDate date]];
|
||||
[d->dp setBordered:NO];
|
||||
[d->dp setBezeled:YES];
|
||||
[d->dp setDrawsBackground:YES];
|
||||
|
@ -23,6 +127,13 @@ static uiDateTimePicker *finishNewDateTimePicker(NSDatePickerElementFlags elemen
|
|||
[d->dp setDatePickerMode:NSSingleDateMode];
|
||||
uiDarwinSetControlFont(d->dp, NSRegularControlSize);
|
||||
|
||||
if (datePickerDelegate == nil) {
|
||||
datePickerDelegate = [[uiprivDatePickerDelegateClass new] autorelease];
|
||||
[uiprivDelegates addObject:datePickerDelegate];
|
||||
}
|
||||
[datePickerDelegate registerPicker:d];
|
||||
uiDateTimePickerOnChanged(d, defaultOnChanged, NULL);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,11 @@ _add_example(histogram
|
|||
${_EXAMPLE_RESOURCES_RC}
|
||||
)
|
||||
|
||||
_add_example(datetime
|
||||
datetime/main.c
|
||||
${_EXAMPLE_RESOURCES_RC}
|
||||
)
|
||||
|
||||
_add_example(cpp-multithread
|
||||
cpp-multithread/main.cpp
|
||||
${_EXAMPLE_RESOURCES_RC}
|
||||
|
@ -53,4 +58,5 @@ add_custom_target(examples
|
|||
histogram
|
||||
cpp-multithread
|
||||
drawtext
|
||||
datetime
|
||||
timer)
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "../../ui.h"
|
||||
|
||||
uiDateTimePicker *dtboth, *dtdate, *dttime;
|
||||
|
||||
const char *timeFormat(uiDateTimePicker *d)
|
||||
{
|
||||
const char *fmt;
|
||||
|
||||
if (d == dtboth)
|
||||
fmt = "%c";
|
||||
else if (d == dtdate)
|
||||
fmt = "%x";
|
||||
else if (d == dttime)
|
||||
fmt = "%X";
|
||||
else
|
||||
fmt = "";
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
void onChanged(uiDateTimePicker *d, void *data)
|
||||
{
|
||||
struct tm time;
|
||||
char buf[64];
|
||||
|
||||
uiDateTimePickerTime(d, &time);
|
||||
strftime(buf, sizeof (buf), timeFormat(d), &time);
|
||||
uiLabelSetText(uiLabel(data), buf);
|
||||
}
|
||||
|
||||
void onClicked(uiButton *b, void *data)
|
||||
{
|
||||
intptr_t now;
|
||||
time_t t;
|
||||
struct tm tmbuf;
|
||||
|
||||
now = (intptr_t) data;
|
||||
t = 0;
|
||||
if (now)
|
||||
t = time(NULL);
|
||||
tmbuf = *localtime(&t);
|
||||
|
||||
if (now) {
|
||||
uiDateTimePickerSetTime(dtdate, &tmbuf);
|
||||
uiDateTimePickerSetTime(dttime, &tmbuf);
|
||||
} else
|
||||
uiDateTimePickerSetTime(dtboth, &tmbuf);
|
||||
}
|
||||
|
||||
int onClosing(uiWindow *w, void *data)
|
||||
{
|
||||
uiQuit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uiInitOptions o;
|
||||
uiWindow *w;
|
||||
uiGrid *g;
|
||||
uiLabel *l;
|
||||
uiButton *b;
|
||||
|
||||
memset(&o, 0, sizeof (uiInitOptions));
|
||||
if (uiInit(&o) != NULL)
|
||||
abort();
|
||||
|
||||
w = uiNewWindow("Date / Time", 320, 240, 0);
|
||||
uiWindowSetMargined(w, 1);
|
||||
|
||||
g = uiNewGrid();
|
||||
uiGridSetPadded(g, 1);
|
||||
uiWindowSetChild(w, uiControl(g));
|
||||
|
||||
dtboth = uiNewDateTimePicker();
|
||||
dtdate = uiNewDatePicker();
|
||||
dttime = uiNewTimePicker();
|
||||
|
||||
uiGridAppend(g, uiControl(dtboth),
|
||||
0, 0, 2, 1,
|
||||
1, uiAlignFill, 0, uiAlignFill);
|
||||
uiGridAppend(g, uiControl(dtdate),
|
||||
0, 1, 1, 1,
|
||||
1, uiAlignFill, 0, uiAlignFill);
|
||||
uiGridAppend(g, uiControl(dttime),
|
||||
1, 1, 1, 1,
|
||||
1, uiAlignFill, 0, uiAlignFill);
|
||||
|
||||
l = uiNewLabel("");
|
||||
uiGridAppend(g, uiControl(l),
|
||||
0, 2, 2, 1,
|
||||
1, uiAlignCenter, 0, uiAlignFill);
|
||||
uiDateTimePickerOnChanged(dtboth, onChanged, l);
|
||||
l = uiNewLabel("");
|
||||
uiGridAppend(g, uiControl(l),
|
||||
0, 3, 1, 1,
|
||||
1, uiAlignCenter, 0, uiAlignFill);
|
||||
uiDateTimePickerOnChanged(dtdate, onChanged, l);
|
||||
l = uiNewLabel("");
|
||||
uiGridAppend(g, uiControl(l),
|
||||
1, 3, 1, 1,
|
||||
1, uiAlignCenter, 0, uiAlignFill);
|
||||
uiDateTimePickerOnChanged(dttime, onChanged, l);
|
||||
|
||||
b = uiNewButton("Now");
|
||||
uiButtonOnClicked(b, onClicked, (void *) 1);
|
||||
uiGridAppend(g, uiControl(b),
|
||||
0, 4, 1, 1,
|
||||
1, uiAlignFill, 1, uiAlignEnd);
|
||||
b = uiNewButton("Unix epoch");
|
||||
uiButtonOnClicked(b, onClicked, (void *) 0);
|
||||
uiGridAppend(g, uiControl(b),
|
||||
1, 4, 1, 1,
|
||||
1, uiAlignFill, 1, uiAlignEnd);
|
||||
|
||||
uiWindowOnClosing(w, onClosing, NULL);
|
||||
uiControlShow(uiControl(w));
|
||||
uiMain();
|
||||
return 0;
|
||||
}
|
5
ui.h
5
ui.h
|
@ -248,8 +248,13 @@ _UI_EXTERN void uiRadioButtonsSetSelected(uiRadioButtons *r, int n);
|
|||
_UI_EXTERN void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data);
|
||||
_UI_EXTERN uiRadioButtons *uiNewRadioButtons(void);
|
||||
|
||||
struct tm;
|
||||
typedef struct uiDateTimePicker uiDateTimePicker;
|
||||
#define uiDateTimePicker(this) ((uiDateTimePicker *) (this))
|
||||
// TODO document that tm_wday and tm_yday are undefined, and tm_isdst should be -1
|
||||
_UI_EXTERN void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time);
|
||||
_UI_EXTERN void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time);
|
||||
_UI_EXTERN void uiDateTimePickerOnChanged(uiDateTimePicker *d, void (*f)(uiDateTimePicker *, void *), void *data);
|
||||
_UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);
|
||||
_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);
|
||||
_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
// 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))
|
||||
#define uiprivDateTimePickerWidgetType (uiprivDateTimePickerWidget_get_type())
|
||||
#define uiprivDateTimePickerWidget(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), uiprivDateTimePickerWidgetType, uiprivDateTimePickerWidget))
|
||||
#define isDateTimePickerWidget(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), uiprivDateTimePickerWidgetType))
|
||||
#define uiprivDateTimePickerWidgetClass(class) (G_TYPE_CHECK_CLASS_CAST((class), uiprivDateTimePickerWidgetType, uiprivDateTimePickerWidgetClass))
|
||||
#define isDateTimePickerWidgetClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), uiprivDateTimePickerWidget))
|
||||
#define getDateTimePickerWidgetClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), uiprivDateTimePickerWidgetType, uiprivDateTimePickerWidgetClass))
|
||||
|
||||
typedef struct dateTimePickerWidget dateTimePickerWidget;
|
||||
typedef struct dateTimePickerWidgetClass dateTimePickerWidgetClass;
|
||||
typedef struct uiprivDateTimePickerWidget uiprivDateTimePickerWidget;
|
||||
typedef struct uiprivDateTimePickerWidgetClass uiprivDateTimePickerWidgetClass;
|
||||
|
||||
struct dateTimePickerWidget {
|
||||
struct uiprivDateTimePickerWidget {
|
||||
GtkToggleButton parent_instance;
|
||||
|
||||
gulong toggledSignal;
|
||||
|
@ -31,6 +31,7 @@ struct dateTimePickerWidget {
|
|||
GtkWidget *seconds;
|
||||
GtkWidget *ampm;
|
||||
|
||||
gulong calendarBlock;
|
||||
gulong hoursBlock;
|
||||
gulong minutesBlock;
|
||||
gulong secondsBlock;
|
||||
|
@ -40,11 +41,11 @@ struct dateTimePickerWidget {
|
|||
GdkDevice *mouse;
|
||||
};
|
||||
|
||||
struct dateTimePickerWidgetClass {
|
||||
struct uiprivDateTimePickerWidgetClass {
|
||||
GtkToggleButtonClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(dateTimePickerWidget, dateTimePickerWidget, GTK_TYPE_TOGGLE_BUTTON)
|
||||
G_DEFINE_TYPE(uiprivDateTimePickerWidget, uiprivDateTimePickerWidget, GTK_TYPE_TOGGLE_BUTTON)
|
||||
|
||||
static int realSpinValue(GtkSpinButton *spinButton)
|
||||
{
|
||||
|
@ -64,7 +65,7 @@ static void setRealSpinValue(GtkSpinButton *spinButton, int value, gulong block)
|
|||
g_signal_handler_unblock(spinButton, block);
|
||||
}
|
||||
|
||||
static GDateTime *selected(dateTimePickerWidget *d)
|
||||
static GDateTime *selected(uiprivDateTimePickerWidget *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;
|
||||
|
@ -84,7 +85,7 @@ static GDateTime *selected(dateTimePickerWidget *d)
|
|||
return g_date_time_new_local(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
static void setLabel(dateTimePickerWidget *d)
|
||||
static void setLabel(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
GDateTime *dt;
|
||||
char *fmt;
|
||||
|
@ -109,14 +110,16 @@ static void setLabel(dateTimePickerWidget *d)
|
|||
g_date_time_unref(dt);
|
||||
}
|
||||
|
||||
static void dateTimeChanged(dateTimePickerWidget *d)
|
||||
static int changedSignal;
|
||||
|
||||
static void dateTimeChanged(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
g_signal_emit(d, changedSignal, 0);
|
||||
setLabel(d);
|
||||
// TODO fire event here
|
||||
}
|
||||
|
||||
// we don't want ::toggled to be sent again
|
||||
static void setActive(dateTimePickerWidget *d, gboolean active)
|
||||
static void setActive(uiprivDateTimePickerWidget *d, gboolean active)
|
||||
{
|
||||
g_signal_handler_block(d, d->toggledSignal);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d), active);
|
||||
|
@ -124,7 +127,7 @@ static void setActive(dateTimePickerWidget *d, gboolean active)
|
|||
}
|
||||
|
||||
// like startGrab() below, a lot of this is in the order that GtkComboBox does it
|
||||
static void endGrab(dateTimePickerWidget *d)
|
||||
static void endGrab(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
if (d->keyboard != NULL)
|
||||
gdk_device_ungrab(d->keyboard, GDK_CURRENT_TIME);
|
||||
|
@ -134,7 +137,7 @@ static void endGrab(dateTimePickerWidget *d)
|
|||
d->mouse = NULL;
|
||||
}
|
||||
|
||||
static void hidePopup(dateTimePickerWidget *d)
|
||||
static void hidePopup(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
endGrab(d);
|
||||
gtk_widget_hide(d->window);
|
||||
|
@ -142,7 +145,7 @@ static void hidePopup(dateTimePickerWidget *d)
|
|||
}
|
||||
|
||||
// this consolidates a good chunk of what GtkComboBox does
|
||||
static gboolean startGrab(dateTimePickerWidget *d)
|
||||
static gboolean startGrab(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
GdkDevice *dev;
|
||||
guint32 time;
|
||||
|
@ -197,7 +200,7 @@ static gboolean startGrab(dateTimePickerWidget *d)
|
|||
}
|
||||
|
||||
// based on gtk_combo_box_list_position() in the GTK+ source code
|
||||
static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y)
|
||||
static void allocationToScreen(uiprivDateTimePickerWidget *d, gint *x, gint *y)
|
||||
{
|
||||
GdkWindow *window;
|
||||
GtkAllocation a;
|
||||
|
@ -237,7 +240,7 @@ static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y)
|
|||
*y = otherY;
|
||||
}
|
||||
|
||||
static void showPopup(dateTimePickerWidget *d)
|
||||
static void showPopup(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
GtkWidget *toplevel;
|
||||
gint x, y;
|
||||
|
@ -259,7 +262,7 @@ static void showPopup(dateTimePickerWidget *d)
|
|||
|
||||
static void onToggled(GtkToggleButton *b, gpointer data)
|
||||
{
|
||||
dateTimePickerWidget *d = dateTimePickerWidget(b);
|
||||
uiprivDateTimePickerWidget *d = uiprivDateTimePickerWidget(b);
|
||||
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d)))
|
||||
showPopup(d);
|
||||
|
@ -269,7 +272,7 @@ static void onToggled(GtkToggleButton *b, gpointer data)
|
|||
|
||||
static gboolean grabBroken(GtkWidget *w, GdkEventGrabBroken *e, gpointer data)
|
||||
{
|
||||
dateTimePickerWidget *d = dateTimePickerWidget(data);
|
||||
uiprivDateTimePickerWidget *d = uiprivDateTimePickerWidget(data);
|
||||
|
||||
hidePopup(d);
|
||||
return TRUE; // this is what GtkComboBox does
|
||||
|
@ -277,7 +280,7 @@ static gboolean grabBroken(GtkWidget *w, GdkEventGrabBroken *e, gpointer data)
|
|||
|
||||
static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data)
|
||||
{
|
||||
dateTimePickerWidget *d = dateTimePickerWidget(data);
|
||||
uiprivDateTimePickerWidget *d = uiprivDateTimePickerWidget(data);
|
||||
int winx, winy;
|
||||
GtkAllocation wina;
|
||||
gboolean in;
|
||||
|
@ -382,12 +385,12 @@ static gboolean ampmSpinboxOutput(GtkSpinButton *sb, gpointer data)
|
|||
|
||||
static void spinboxChanged(GtkSpinButton *sb, gpointer data)
|
||||
{
|
||||
dateTimePickerWidget *d = dateTimePickerWidget(data);
|
||||
uiprivDateTimePickerWidget *d = uiprivDateTimePickerWidget(data);
|
||||
|
||||
dateTimeChanged(d);
|
||||
}
|
||||
|
||||
static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, gint (*input)(GtkSpinButton *, gpointer, gpointer), gboolean (*output)(GtkSpinButton *, gpointer), gulong *block)
|
||||
static GtkWidget *newSpinbox(uiprivDateTimePickerWidget *d, int min, int max, gint (*input)(GtkSpinButton *, gpointer, gpointer), gboolean (*output)(GtkSpinButton *, gpointer), gulong *block)
|
||||
{
|
||||
GtkWidget *sb;
|
||||
|
||||
|
@ -405,30 +408,52 @@ static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, gint (*i
|
|||
|
||||
static void dateChanged(GtkCalendar *c, gpointer data)
|
||||
{
|
||||
dateTimePickerWidget *d = dateTimePickerWidget(data);
|
||||
uiprivDateTimePickerWidget *d = uiprivDateTimePickerWidget(data);
|
||||
|
||||
dateTimeChanged(d);
|
||||
}
|
||||
|
||||
static void setDateOnly(dateTimePickerWidget *d)
|
||||
static void setDateOnly(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
d->hasTime = FALSE;
|
||||
gtk_container_remove(GTK_CONTAINER(d->box), d->timebox);
|
||||
}
|
||||
|
||||
static void setTimeOnly(dateTimePickerWidget *d)
|
||||
static void setTimeOnly(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
d->hasDate = FALSE;
|
||||
gtk_container_remove(GTK_CONTAINER(d->box), d->calendar);
|
||||
}
|
||||
|
||||
static void dateTimePickerWidget_init(dateTimePickerWidget *d)
|
||||
static void uiprivDateTimePickerWidget_setTime(uiprivDateTimePickerWidget *d, GDateTime *dt)
|
||||
{
|
||||
GDateTime *dt;
|
||||
gint year, month, day;
|
||||
gint hour;
|
||||
gulong calendarBlock;
|
||||
|
||||
// notice how we block signals from firing
|
||||
if (d->hasDate) {
|
||||
g_date_time_get_ymd(dt, &year, &month, &day);
|
||||
month--; // GDateTime/GtkCalendar differences
|
||||
g_signal_handler_block(d->calendar, d->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, d->calendarBlock);
|
||||
}
|
||||
if (d->hasTime) {
|
||||
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 uiprivDateTimePickerWidget_init(uiprivDateTimePickerWidget *d)
|
||||
{
|
||||
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));
|
||||
|
@ -446,7 +471,7 @@ static void dateTimePickerWidget_init(dateTimePickerWidget *d)
|
|||
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);
|
||||
d->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);
|
||||
|
@ -493,53 +518,103 @@ static void dateTimePickerWidget_init(dateTimePickerWidget *d)
|
|||
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);
|
||||
uiprivDateTimePickerWidget_setTime(d, g_date_time_new_now_local());
|
||||
}
|
||||
|
||||
static void dateTimePickerWidget_dispose(GObject *obj)
|
||||
static void uiprivDateTimePickerWidget_dispose(GObject *obj)
|
||||
{
|
||||
dateTimePickerWidget *d = dateTimePickerWidget(obj);
|
||||
uiprivDateTimePickerWidget *d = uiprivDateTimePickerWidget(obj);
|
||||
|
||||
if (d->window != NULL) {
|
||||
gtk_widget_destroy(d->window);
|
||||
d->window = NULL;
|
||||
}
|
||||
G_OBJECT_CLASS(dateTimePickerWidget_parent_class)->dispose(obj);
|
||||
G_OBJECT_CLASS(uiprivDateTimePickerWidget_parent_class)->dispose(obj);
|
||||
}
|
||||
|
||||
static void dateTimePickerWidget_finalize(GObject *obj)
|
||||
static void uiprivDateTimePickerWidget_finalize(GObject *obj)
|
||||
{
|
||||
G_OBJECT_CLASS(dateTimePickerWidget_parent_class)->finalize(obj);
|
||||
G_OBJECT_CLASS(uiprivDateTimePickerWidget_parent_class)->finalize(obj);
|
||||
}
|
||||
|
||||
static void dateTimePickerWidget_class_init(dateTimePickerWidgetClass *class)
|
||||
static void uiprivDateTimePickerWidget_class_init(uiprivDateTimePickerWidgetClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS(class)->dispose = dateTimePickerWidget_dispose;
|
||||
G_OBJECT_CLASS(class)->finalize = dateTimePickerWidget_finalize;
|
||||
G_OBJECT_CLASS(class)->dispose = uiprivDateTimePickerWidget_dispose;
|
||||
G_OBJECT_CLASS(class)->finalize = uiprivDateTimePickerWidget_finalize;
|
||||
|
||||
changedSignal = g_signal_new("changed",
|
||||
G_TYPE_FROM_CLASS(class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
}
|
||||
|
||||
struct uiDateTimePicker {
|
||||
uiUnixControl c;
|
||||
GtkWidget *widget;
|
||||
uiprivDateTimePickerWidget *d;
|
||||
void (*onChanged)(uiDateTimePicker *, void *);
|
||||
void *onChangedData;
|
||||
};
|
||||
|
||||
uiUnixControlAllDefaults(uiDateTimePicker)
|
||||
|
||||
static void defaultOnChanged(uiDateTimePicker *d, void *data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tmbuf;
|
||||
GDateTime *dt;
|
||||
|
||||
dt = selected(d->d);
|
||||
t = g_date_time_to_unix(dt);
|
||||
g_date_time_unref(dt);
|
||||
|
||||
// Copy time to minimize a race condition
|
||||
// time.h functions use global non-thread-safe data
|
||||
tmbuf = *localtime(&t);
|
||||
memcpy(time, &tmbuf, sizeof(struct tm));
|
||||
}
|
||||
|
||||
void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tmbuf;
|
||||
|
||||
// Copy time because mktime() modifies its argument
|
||||
memcpy(&tmbuf, time, sizeof(struct tm));
|
||||
t = mktime(&tmbuf);
|
||||
|
||||
uiprivDateTimePickerWidget_setTime(d->d, g_date_time_new_from_unix_local(t));
|
||||
dateTimeChanged(d->d);
|
||||
}
|
||||
|
||||
void uiDateTimePickerOnChanged(uiDateTimePicker *d, void (*f)(uiDateTimePicker *, void *), void *data)
|
||||
{
|
||||
d->onChanged = f;
|
||||
d->onChangedData = data;
|
||||
}
|
||||
|
||||
static void onChanged(uiprivDateTimePickerWidget *d, gpointer data)
|
||||
{
|
||||
uiDateTimePicker *c;
|
||||
|
||||
c = uiDateTimePicker(data);
|
||||
(*(c->onChanged))(c, c->onChangedData);
|
||||
}
|
||||
|
||||
static GtkWidget *newDTP(void)
|
||||
{
|
||||
GtkWidget *w;
|
||||
|
||||
w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL));
|
||||
setLabel(dateTimePickerWidget(w));
|
||||
w = GTK_WIDGET(g_object_new(uiprivDateTimePickerWidgetType, "label", "", NULL));
|
||||
setLabel(uiprivDateTimePickerWidget(w));
|
||||
return w;
|
||||
}
|
||||
|
||||
|
@ -547,9 +622,9 @@ static GtkWidget *newDP(void)
|
|||
{
|
||||
GtkWidget *w;
|
||||
|
||||
w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL));
|
||||
setDateOnly(dateTimePickerWidget(w));
|
||||
setLabel(dateTimePickerWidget(w));
|
||||
w = GTK_WIDGET(g_object_new(uiprivDateTimePickerWidgetType, "label", "", NULL));
|
||||
setDateOnly(uiprivDateTimePickerWidget(w));
|
||||
setLabel(uiprivDateTimePickerWidget(w));
|
||||
return w;
|
||||
}
|
||||
|
||||
|
@ -557,20 +632,12 @@ static GtkWidget *newTP(void)
|
|||
{
|
||||
GtkWidget *w;
|
||||
|
||||
w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL));
|
||||
setTimeOnly(dateTimePickerWidget(w));
|
||||
setLabel(dateTimePickerWidget(w));
|
||||
w = GTK_WIDGET(g_object_new(uiprivDateTimePickerWidgetType, "label", "", NULL));
|
||||
setTimeOnly(uiprivDateTimePickerWidget(w));
|
||||
setLabel(uiprivDateTimePickerWidget(w));
|
||||
return w;
|
||||
}
|
||||
|
||||
struct uiDateTimePicker {
|
||||
uiUnixControl c;
|
||||
GtkWidget *widget;
|
||||
dateTimePickerWidget *d;
|
||||
};
|
||||
|
||||
uiUnixControlAllDefaults(uiDateTimePicker)
|
||||
|
||||
uiDateTimePicker *finishNewDateTimePicker(GtkWidget *(*fn)(void))
|
||||
{
|
||||
uiDateTimePicker *d;
|
||||
|
@ -578,7 +645,9 @@ uiDateTimePicker *finishNewDateTimePicker(GtkWidget *(*fn)(void))
|
|||
uiUnixNewControl(uiDateTimePicker, d);
|
||||
|
||||
d->widget = (*fn)();
|
||||
d->d = dateTimePickerWidget(d->widget);
|
||||
d->d = uiprivDateTimePickerWidget(d->widget);
|
||||
g_signal_connect(d->widget, "changed", G_CALLBACK(onChanged), d);
|
||||
uiDateTimePickerOnChanged(d, defaultOnChanged, NULL);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
struct uiDateTimePicker {
|
||||
uiWindowsControl c;
|
||||
HWND hwnd;
|
||||
void(*onChanged)(uiDateTimePicker *, void *);
|
||||
void *onChangedData;
|
||||
};
|
||||
|
||||
// utility functions
|
||||
|
@ -103,6 +105,7 @@ static void uiDateTimePickerDestroy(uiControl *c)
|
|||
uiDateTimePicker *d = uiDateTimePicker(c);
|
||||
|
||||
uiWindowsUnregisterReceiveWM_WININICHANGE(d->hwnd);
|
||||
uiWindowsUnregisterWM_NOTIFYHandler(d->hwnd);
|
||||
uiWindowsEnsureDestroyWindow(d->hwnd);
|
||||
uiFreeControl(uiControl(d));
|
||||
}
|
||||
|
@ -131,6 +134,72 @@ static void uiDateTimePickerMinimumSize(uiWindowsControl *c, int *width, int *he
|
|||
*height = y;
|
||||
}
|
||||
|
||||
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
|
||||
{
|
||||
uiDateTimePicker *d = uiDateTimePicker(c);
|
||||
|
||||
if (nmhdr->code != DTN_DATETIMECHANGE)
|
||||
return FALSE;
|
||||
(*(d->onChanged))(d, d->onChangedData);
|
||||
*lResult = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void fromSystemTime(SYSTEMTIME *systime, struct tm *time)
|
||||
{
|
||||
ZeroMemory(time, sizeof (struct tm));
|
||||
time->tm_sec = systime->wSecond;
|
||||
time->tm_min = systime->wMinute;
|
||||
time->tm_hour = systime->wHour;
|
||||
time->tm_mday = systime->wDay;
|
||||
time->tm_mon = systime->wMonth - 1;
|
||||
time->tm_year = systime->wYear - 1900;
|
||||
time->tm_wday = systime->wDayOfWeek;
|
||||
time->tm_isdst = -1;
|
||||
}
|
||||
|
||||
static void toSystemTime(const struct tm *time, SYSTEMTIME *systime)
|
||||
{
|
||||
ZeroMemory(systime, sizeof (SYSTEMTIME));
|
||||
systime->wYear = time->tm_year + 1900;
|
||||
systime->wMonth = time->tm_mon + 1;
|
||||
systime->wDayOfWeek = time->tm_wday;
|
||||
systime->wDay = time->tm_mday;
|
||||
systime->wHour = time->tm_hour;
|
||||
systime->wMinute = time->tm_min;
|
||||
systime->wSecond = time->tm_sec;
|
||||
}
|
||||
|
||||
static void defaultOnChanged(uiDateTimePicker *d, void *data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time)
|
||||
{
|
||||
SYSTEMTIME systime;
|
||||
|
||||
if (SendMessageW(d->hwnd, DTM_GETSYSTEMTIME, 0, (LPARAM) (&systime)) != GDT_VALID)
|
||||
logLastError(L"error getting date and time");
|
||||
fromSystemTime(&systime, time);
|
||||
}
|
||||
|
||||
void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time)
|
||||
{
|
||||
SYSTEMTIME systime;
|
||||
|
||||
toSystemTime(time, &systime);
|
||||
if (SendMessageW(d->hwnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM) (&systime)) == 0)
|
||||
logLastError(L"error setting date and time");
|
||||
(*(d->onChanged))(d, d->onChangedData);
|
||||
}
|
||||
|
||||
void uiDateTimePickerOnChanged(uiDateTimePicker *d, void(*f)(uiDateTimePicker *, void *), void *data)
|
||||
{
|
||||
d->onChanged = f;
|
||||
d->onChangedData = data;
|
||||
}
|
||||
|
||||
static uiDateTimePicker *finishNewDateTimePicker(DWORD style)
|
||||
{
|
||||
uiDateTimePicker *d;
|
||||
|
@ -147,6 +216,8 @@ static uiDateTimePicker *finishNewDateTimePicker(DWORD style)
|
|||
// for the standard styles, this is in the date-time picker itself
|
||||
// for our date/time mode, we do it in a subclass assigned in uiNewDateTimePicker()
|
||||
uiWindowsRegisterReceiveWM_WININICHANGE(d->hwnd);
|
||||
uiWindowsRegisterWM_NOTIFYHandler(d->hwnd, onWM_NOTIFY, uiControl(d));
|
||||
uiDateTimePickerOnChanged(d, defaultOnChanged, NULL);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue