00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00029
00030 #include <gtk/gtk.h>
00031
00032
00033
00034
00035 #include "ergtklog.h"
00036 #include "erGtkSelectionGroup.h"
00037
00038
00039
00040 static GtkEventBoxClass* g_parent_class = NULL;
00041
00042
00043 enum
00044 {
00045 SELECTION_UPDATE,
00046 LAST_SIGNAL,
00047 };
00048
00049 static gint g_signals[LAST_SIGNAL];
00050
00051
00052
00053
00054
00055
00056
00057 static void add_buttons(erGtkSelectionGroup *item, GtkToggleButton** button_tbl);
00058
00059
00060 static gboolean real_set_details(erGtkSelectionGroup *item, const guint min_selected, const guint max_selected);
00061 static void real_freeze_buttons(erGtkSelectionGroup *item, const gboolean freeze);
00062 static GtkToggleButton* real_get_button(erGtkSelectionGroup *item, const guint button_id);
00063 static void real_get_selected_buttons(erGtkSelectionGroup *item, gint* button_ids, const guint len);
00064
00065
00066 static void ergtk_selection_group_class_init(erGtkSelectionGroupClass* klass);
00067 static void ergtk_selection_group_init(erGtkSelectionGroup* selection);
00068 static void ergtk_selection_group_dispose(GObject* object);
00069 static void ergtk_selection_group_finalize(GObject* object);
00070 static void on_button_toggled(GtkToggleButton* button, gpointer user_data);
00071 static gboolean on_delayed_select_button(gpointer user_data);
00072 static gboolean on_delayed_deselect_button(gpointer user_data);
00073
00074
00075
00076 GtkWidget *ergtk_selection_group_new(GtkToggleButton** button_tbl)
00077 {
00078 GtkToggleButton** p_button;
00079
00080
00081 for (p_button = button_tbl ; *p_button ; p_button++)
00082 {
00083 g_return_val_if_fail(GTK_IS_TOGGLE_BUTTON(*p_button), FALSE);
00084 }
00085
00086
00087 erGtkSelectionGroup* item = (erGtkSelectionGroup*) g_object_new(ERGTK_SELECTION_GROUP_TYPE, NULL);
00088
00089
00090 add_buttons(item, button_tbl);
00091
00092 return GTK_WIDGET(item);
00093 }
00094
00095 static void add_buttons(erGtkSelectionGroup *item, GtkToggleButton** button_tbl)
00096 {
00097 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item));
00098 g_return_if_fail(item->buttons == NULL);
00099 g_return_if_fail(item->history == NULL);
00100
00101 GtkToggleButton* button;
00102 GtkToggleButton** p_button;
00103
00104
00105 for (p_button = button_tbl ; *p_button ; p_button++)
00106 {
00107 button = *p_button;
00108 g_object_ref(G_OBJECT(button));
00109 g_signal_connect_after(G_OBJECT(button), "toggled", G_CALLBACK(on_button_toggled), item);
00110 item->buttons = g_slist_append(item->buttons, button);
00111
00112 if (gtk_toggle_button_get_active(button))
00113 {
00114 item->history = g_slist_append(item->history, button);
00115 }
00116 }
00117 }
00118
00119
00120 GType ergtk_selection_group_get_type(void)
00121 {
00122 static GType class_type = 0;
00123
00124 if (class_type == 0)
00125 {
00126 static const GTypeInfo class_info =
00127 {
00128 sizeof(erGtkSelectionGroupClass),
00129 NULL,
00130 NULL,
00131 (GClassInitFunc) ergtk_selection_group_class_init,
00132 NULL,
00133 NULL,
00134 sizeof(erGtkSelectionGroup),
00135 0,
00136 (GInstanceInitFunc) ergtk_selection_group_init,
00137 };
00138
00139 class_type = g_type_register_static(GTK_TYPE_EVENT_BOX, "erGtkSelectionGroup", &class_info, 0);
00140 }
00141 return class_type;
00142 }
00143
00144
00145 static void ergtk_selection_group_class_init(erGtkSelectionGroupClass* klass)
00146 {
00147 GObjectClass* object_class = (GObjectClass *)klass;
00148
00149
00150 g_parent_class = g_type_class_peek_parent(klass);
00151
00152
00153 object_class->dispose = ergtk_selection_group_dispose;
00154 object_class->finalize = ergtk_selection_group_finalize;
00155
00156 klass->set_details = real_set_details;
00157 klass->freeze_buttons = real_freeze_buttons;
00158 klass->get_button = real_get_button;
00159 klass->get_selected_buttons = real_get_selected_buttons;
00160 klass->add_buttons = add_buttons;
00161
00162
00163 g_signals[SELECTION_UPDATE] = g_signal_new( "selection_update",
00164 G_OBJECT_CLASS_TYPE(object_class),
00165 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
00166 G_STRUCT_OFFSET(erGtkSelectionGroupClass, selection_update),
00167 NULL,
00168 NULL,
00169 gtk_marshal_VOID__POINTER,
00170 G_TYPE_NONE,
00171 1,
00172 G_TYPE_POINTER );
00173 }
00174
00175
00176 static void ergtk_selection_group_init(erGtkSelectionGroup* item)
00177 {
00178 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item));
00179
00180
00181 item->dispose_has_run = FALSE;
00182 item->buttons = NULL;
00183 item->min_selected = 0;
00184 item->max_selected = 9999;
00185 item->freeze_buttons = FALSE;
00186 item->history = NULL;
00187 }
00188
00189
00190 static void ergtk_selection_group_dispose(GObject* object)
00191 {
00192 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(object));
00193
00194 erGtkSelectionGroup* item = (erGtkSelectionGroup*)object;
00195
00196
00197 if (!item->dispose_has_run)
00198 {
00199 item->dispose_has_run = TRUE;
00200
00201 g_slist_foreach(item->buttons, (GFunc)g_object_unref, NULL);
00202 }
00203
00204
00205 GObjectClass* parent_object_class = G_OBJECT_CLASS(g_parent_class);
00206 if (parent_object_class->dispose)
00207 {
00208 parent_object_class->dispose(object);
00209 }
00210 }
00211
00212
00213 static void ergtk_selection_group_finalize(GObject* object)
00214 {
00215 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(object));
00216
00217 erGtkSelectionGroup* item = (erGtkSelectionGroup*)object;
00218
00219
00220 if (item->buttons)
00221 {
00222 g_slist_free(item->buttons);
00223 }
00224 if (item->history)
00225 {
00226 g_slist_free(item->history);
00227 }
00228
00229
00230 GObjectClass* parent_object_class = G_OBJECT_CLASS(g_parent_class);
00231 if (parent_object_class->finalize)
00232 {
00233 parent_object_class->finalize(object);
00234 }
00235 }
00236
00237
00238 gboolean ergtk_selection_group_set_details(erGtkSelectionGroup *item, const guint min_selected, const guint max_selected)
00239 {
00240 LOGPRINTF("entry: item [%p] min [%u] max [%u]", item, min_selected, max_selected);
00241 g_return_val_if_fail(ERGTK_IS_SELECTION_GROUP(item), FALSE);
00242 g_return_val_if_fail((item->dispose_has_run == FALSE), FALSE);
00243
00244 erGtkSelectionGroupClass* klass = ERGTK_SELECTION_GROUP_GET_CLASS(item);
00245
00246
00247 if (klass->set_details)
00248 {
00249 return klass->set_details(item, min_selected, max_selected);
00250 }
00251 else
00252 {
00253 return FALSE;
00254 }
00255 }
00256
00257 static gboolean real_set_details(erGtkSelectionGroup *item, const guint min_selected, const guint max_selected)
00258 {
00259 LOGPRINTF("entry: item [%p] min [%u] max [%u]", item, min_selected, max_selected);
00260 g_return_val_if_fail(ERGTK_IS_SELECTION_GROUP(item), FALSE);
00261 g_return_val_if_fail((item->dispose_has_run == FALSE), FALSE);
00262
00263 gint num_buttons = g_slist_length(item->buttons);
00264 g_return_val_if_fail(min_selected <= max_selected, FALSE);
00265 g_return_val_if_fail(min_selected <= num_buttons, FALSE);
00266 g_return_val_if_fail(max_selected >= 0, FALSE);
00267
00268 GSList* history_last = g_slist_last(item->history);
00269 GSList* buttons_last_selected = history_last ? g_slist_find(item->buttons, history_last->data) : NULL;
00270
00271 GtkToggleButton* button_tmp = NULL;
00272
00273
00274 item->min_selected = min_selected;
00275 item->max_selected = max_selected;
00276
00277
00278 gint num_selected = g_slist_length(item->history);
00279 LOGPRINTF("num_buttons [%d] num_selected [%d]", num_buttons, num_selected);
00280 while (num_selected < min_selected)
00281 {
00282
00283 if (buttons_last_selected)
00284 {
00285 buttons_last_selected = g_slist_next(buttons_last_selected);
00286 }
00287 else
00288 {
00289 buttons_last_selected = item->buttons;
00290 }
00291 item->history = g_slist_append(item->history, buttons_last_selected->data);
00292 history_last = g_slist_last(item->history);
00293 num_selected++;
00294
00295
00296
00297
00298 gtk_toggle_button_set_active(buttons_last_selected->data, TRUE);
00299 }
00300 while (num_selected > max_selected)
00301 {
00302
00303 button_tmp = history_last->data;
00304 item->history = g_slist_delete_link(item->history, history_last);
00305 history_last = g_slist_last(item->history);
00306 num_selected--;
00307
00308
00309
00310
00311 gtk_toggle_button_set_active(button_tmp, FALSE);
00312 }
00313
00314 LOGPRINTF("leave: num_selected [%d] history_length [%d]", num_selected, g_slist_length(item->history));
00315 return TRUE;
00316 }
00317
00318
00319 void ergtk_selection_group_freeze_buttons(erGtkSelectionGroup *item,
00320 const gboolean freeze)
00321 {
00322 LOGPRINTF("entry: item [%p] freeze [%d]", item, freeze);
00323 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item));
00324 g_return_if_fail((item->dispose_has_run == FALSE));
00325
00326 erGtkSelectionGroupClass* klass = ERGTK_SELECTION_GROUP_GET_CLASS(item);
00327
00328
00329 if (klass->freeze_buttons)
00330 {
00331 klass->freeze_buttons(item, freeze);
00332 }
00333 }
00334
00335 static void real_freeze_buttons(erGtkSelectionGroup *item,
00336 const gboolean freeze)
00337 {
00338 LOGPRINTF("entry: item [%p] freeze [%d]", item, freeze);
00339 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item));
00340 g_return_if_fail((item->dispose_has_run == FALSE));
00341
00342 item->freeze_buttons = freeze;
00343 }
00344
00345
00346 GtkToggleButton* ergtk_selection_group_get_button(erGtkSelectionGroup *item, const guint button_id)
00347 {
00348 LOGPRINTF("entry: item [%p] button_id [%d]", item, button_id);
00349 g_return_val_if_fail(ERGTK_IS_SELECTION_GROUP(item), NULL);
00350 g_return_val_if_fail((item->dispose_has_run == FALSE), NULL);
00351
00352 erGtkSelectionGroupClass* klass = ERGTK_SELECTION_GROUP_GET_CLASS(item);
00353
00354
00355 if (klass->get_button)
00356 {
00357 return klass->get_button(item, button_id);
00358 }
00359 else
00360 {
00361 return NULL;
00362 }
00363 }
00364
00365 static GtkToggleButton* real_get_button(erGtkSelectionGroup *item, const guint button_id)
00366 {
00367 LOGPRINTF("entry: item [%p] button_id [%d]", item, button_id);
00368 g_return_val_if_fail(ERGTK_IS_SELECTION_GROUP(item), NULL);
00369 g_return_val_if_fail((item->dispose_has_run == FALSE), NULL);
00370
00371 GtkToggleButton* button = g_slist_nth_data(item->buttons, button_id);
00372
00373 return button;
00374 }
00375
00376
00377 void ergtk_selection_group_get_selected_buttons(erGtkSelectionGroup *item, gint* button_ids, const guint len)
00378 {
00379 LOGPRINTF("entry: item [%p]", item);
00380 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item));
00381 g_return_if_fail((item->dispose_has_run == FALSE));
00382
00383 erGtkSelectionGroupClass* klass = ERGTK_SELECTION_GROUP_GET_CLASS(item);
00384
00385
00386 if (klass->get_selected_buttons)
00387 {
00388 klass->get_selected_buttons(item, button_ids, len);
00389 }
00390 }
00391
00392 static void real_get_selected_buttons(erGtkSelectionGroup *item, gint* button_ids, const guint len)
00393 {
00394 LOGPRINTF("entry: item [%p]", item);
00395 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item) );
00396 g_return_if_fail((item->dispose_has_run == FALSE));
00397
00398 int i;
00399 GSList* history = item->history;
00400
00401 for (i = 0 ; i < len ; i++)
00402 {
00403 if (history)
00404 {
00405 button_ids[i] = g_slist_index(item->buttons, history->data);
00406 history = g_slist_next(history);
00407 }
00408 else
00409 {
00410 button_ids[i] = -1;
00411 }
00412 LOGPRINTF("button_id[%d] = [%d]", i, button_ids[i]);
00413 }
00414 }
00415
00416
00417
00418 static void on_button_toggled(GtkToggleButton* button, gpointer user_data)
00419 {
00420 LOGPRINTF("entry: button [%p] item [%p]", button, user_data);
00421 erGtkSelectionGroup* item = (erGtkSelectionGroup*)user_data;
00422
00423 g_return_if_fail(ERGTK_IS_SELECTION_GROUP(item));
00424 g_return_if_fail((item)->dispose_has_run == FALSE);
00425
00426 gboolean active = gtk_toggle_button_get_active(button);
00427 GSList* history_button = g_slist_find(item->history, button);
00428 guint history_length = g_slist_length(item->history);
00429 LOGPRINTF("active [%d] history_button [%p] history_len [%u]",
00430 active, history_button, history_length);
00431
00432 GtkToggleButton* button_tmp;
00433
00434 if (item->freeze_buttons)
00435 {
00436
00437 if (history_button)
00438 {
00439
00440 if (!active)
00441 {
00442 g_timeout_add(500, on_delayed_select_button, (gpointer)button);
00443 }
00444 }
00445 else
00446 {
00447
00448 if (active)
00449 {
00450 g_timeout_add(500, on_delayed_deselect_button, (gpointer)button);
00451 }
00452 }
00453 }
00454 else
00455 {
00456
00457 if (active)
00458 {
00459 if (history_button == NULL)
00460 {
00461
00462 LOGPRINTF("add button [%p] to history", button);
00463 item->history = g_slist_append(item->history, button);
00464 history_length++;
00465
00466
00467 LOGPRINTF("enforce [%d] history_len [%d] max_selected [%d]",
00468 item->enforce_max_selected, history_length, item->max_selected);
00469 if (history_length > item->max_selected)
00470 {
00471
00472
00473 button_tmp = GTK_TOGGLE_BUTTON(item->history->data);
00474 LOGPRINTF("remove button [%p] to history", button_tmp);
00475 item->history = g_slist_delete_link(item->history, item->history);
00476
00477
00478
00479 gtk_toggle_button_set_active(button_tmp, FALSE);
00480 LOGPRINTF("button [%p] set to not-active", button_tmp);
00481 }
00482 }
00483 else
00484 {
00485
00486 }
00487 }
00488 else
00489 {
00490 if (history_button)
00491 {
00492 LOGPRINTF("enforce [%d] history_len [%d] min_selected [%d]",
00493 item->enforce_min_selected, history_length, item->min_selected);
00494 if (history_length > item->min_selected)
00495 {
00496
00497
00498 item->history = g_slist_delete_link(item->history, history_button);
00499 }
00500 else
00501 {
00502
00503 g_timeout_add(500, on_delayed_select_button, (gpointer)button);
00504 }
00505 }
00506 else
00507 {
00508
00509 }
00510 }
00511 }
00512
00513
00514 g_signal_emit(item, g_signals[SELECTION_UPDATE], 0, (gpointer)button);
00515 }
00516
00517 static gboolean on_delayed_select_button(gpointer user_data)
00518 {
00519 LOGPRINTF("entry: button [%p]", user_data);
00520
00521
00522 GtkToggleButton* button = (GtkToggleButton*)user_data;
00523
00524 g_return_val_if_fail(GTK_IS_TOGGLE_BUTTON(button), FALSE);
00525
00526 gtk_toggle_button_set_active(button, TRUE);
00527
00528 return FALSE;
00529 }
00530
00531 static gboolean on_delayed_deselect_button(gpointer user_data)
00532 {
00533 LOGPRINTF("entry: button [%p]", user_data);
00534
00535
00536 GtkToggleButton* button = (GtkToggleButton*)user_data;
00537
00538 g_return_val_if_fail(GTK_IS_TOGGLE_BUTTON(button), FALSE);
00539
00540 gtk_toggle_button_set_active(button, FALSE);
00541
00542 return FALSE;
00543 }
00544
00545 gint ergtk_selection_group_get_length(erGtkSelectionGroup *item)
00546 {
00547 LOGPRINTF("entry: item [%p]", item);
00548
00549 gint num_buttons = 0;
00550
00551 g_return_val_if_fail(ERGTK_IS_SELECTION_GROUP(item), 0);
00552 g_return_val_if_fail(item->buttons, 0);
00553
00554 num_buttons = g_slist_length(item->buttons);
00555
00556 LOGPRINTF("%d buttons cotrolled by erGtkSelectionGroup [%p]",num_buttons, item);
00557
00558 return num_buttons;
00559 }
00560