preliminary guild view in the side bar
This commit is contained in:
		
							parent
							
								
									b879151e07
								
							
						
					
					
						commit
						af49931b49
					
				| @ -21,27 +21,27 @@ typedef enum { | ||||
| 
 | ||||
|     /* A direct message channel for 1:1 communication
 | ||||
|      */ | ||||
|     CHANNEL_TYPE_DM, | ||||
|     CHANNEL_TYPE_DM = 1, | ||||
| 
 | ||||
|     /* A guild voice channel
 | ||||
|      */ | ||||
|     CHANNEL_TYPE_GUILD_VOICE, | ||||
|     CHANNEL_TYPE_GUILD_VOICE = 2, | ||||
| 
 | ||||
|     /* Group direct message channel 1:N communication
 | ||||
|      */ | ||||
|     CHANNEL_TYPE_GROUP_DM, | ||||
|     CHANNEL_TYPE_GROUP_DM = 3, | ||||
| 
 | ||||
|     /* Category within a GUILD
 | ||||
|      */ | ||||
|     CHANNEL_TYPE_GUILD_CATEGORY, | ||||
|     CHANNEL_TYPE_GUILD_CATEGORY = 4, | ||||
| 
 | ||||
|     /* News channel
 | ||||
|      */ | ||||
|     CHANNEL_TYPE_GUILD_NEWS, | ||||
|     CHANNEL_TYPE_GUILD_NEWS = 5, | ||||
| 
 | ||||
|     /* Guild store, no idea what this is
 | ||||
|      */ | ||||
|     CHANNEL_TYPE_GUILD_STORE, | ||||
|     CHANNEL_TYPE_GUILD_STORE = 6, | ||||
| } dc_channel_type_t; | ||||
| 
 | ||||
| struct dc_channel_; | ||||
| @ -51,6 +51,7 @@ dc_channel_t dc_channel_new(void); | ||||
| dc_channel_t dc_channel_from_json(json_t *j); | ||||
| 
 | ||||
| char const *dc_channel_id(dc_channel_t c); | ||||
| char const *dc_channel_name(dc_channel_t c); | ||||
| 
 | ||||
| dc_channel_type_t dc_channel_type(dc_channel_t c); | ||||
| bool dc_channel_is_dm(dc_channel_t c); | ||||
|  | ||||
| @ -1,12 +1,21 @@ | ||||
| #ifndef DC_GUILD_H | ||||
| #define DC_GUILD_H | ||||
| 
 | ||||
| #include <dc/channel.h> | ||||
| 
 | ||||
| #include <jansson.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| /* Discords version of groups or chat servers
 | ||||
|  */ | ||||
| struct dc_guild_; | ||||
| typedef struct dc_guild_ *dc_guild_t; | ||||
| 
 | ||||
| dc_guild_t dc_guild_new(void); | ||||
| dc_guild_t dc_guild_from_json(json_t *j); | ||||
| 
 | ||||
| size_t dc_guild_channels(dc_guild_t d); | ||||
| dc_channel_t dc_guild_nth_channel(dc_guild_t d, size_t idx); | ||||
| 
 | ||||
| char const *dc_guild_name(dc_guild_t d); | ||||
| void dc_guild_set_name(dc_guild_t d, char const *val); | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
| #include <dc/account.h> | ||||
| #include <dc/channel.h> | ||||
| #include <dc/gateway.h> | ||||
| #include <dc/guild.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * A session object will contain all information gathered after a user | ||||
| @ -86,6 +87,12 @@ dc_channel_t dc_session_make_channel(dc_session_t s, dc_account_t *r, | ||||
| dc_channel_t dc_session_channel_recipients(dc_session_t s, | ||||
|                                            dc_account_t *r, size_t sz); | ||||
| 
 | ||||
| /**
 | ||||
|  * Add a guild to be managed by this session. | ||||
|  */ | ||||
| void dc_session_add_guild(dc_session_t s, dc_guild_t g); | ||||
| GHashTable *dc_session_guilds(dc_session_t s); | ||||
| 
 | ||||
| /**
 | ||||
|  * comparision functions for sorting, and finding | ||||
|  */ | ||||
|  | ||||
| @ -124,7 +124,7 @@ dc_channel_t dc_channel_from_json(json_t *j) | ||||
|     } | ||||
| 
 | ||||
|     v = json_object_get(j, "name"); | ||||
|     if (v == NULL && json_is_string(v)) { | ||||
|     if (v != NULL && json_is_string(v)) { | ||||
|         c->name = strdup(json_string_value(v)); | ||||
|     } | ||||
| 
 | ||||
| @ -237,6 +237,12 @@ json_t *dc_channel_to_json(dc_channel_t c) | ||||
|     return j; | ||||
| } | ||||
| 
 | ||||
| char const *dc_channel_name(dc_channel_t c) | ||||
| { | ||||
|     return_if_true(c == NULL, NULL); | ||||
|     return c->name; | ||||
| } | ||||
| 
 | ||||
| char const *dc_channel_id(dc_channel_t c) | ||||
| { | ||||
|     return_if_true(c == NULL, NULL); | ||||
|  | ||||
| @ -9,6 +9,8 @@ struct dc_guild_ | ||||
| 
 | ||||
|     char *name; | ||||
|     char *id; | ||||
| 
 | ||||
|     GPtrArray *channels; | ||||
| }; | ||||
| 
 | ||||
| static void dc_guild_free(dc_guild_t ptr) | ||||
| @ -16,6 +18,11 @@ static void dc_guild_free(dc_guild_t ptr) | ||||
|     free(ptr->name); | ||||
|     free(ptr->id); | ||||
| 
 | ||||
|     if (ptr->channels != NULL) { | ||||
|         g_ptr_array_unref(ptr->channels); | ||||
|         ptr->channels = NULL; | ||||
|     } | ||||
| 
 | ||||
|     free(ptr); | ||||
| } | ||||
| 
 | ||||
| @ -26,9 +33,64 @@ dc_guild_t dc_guild_new(void) | ||||
| 
 | ||||
|     p->ref.cleanup = (dc_cleanup_t)dc_guild_free; | ||||
| 
 | ||||
|     p->channels = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref); | ||||
|     if (p->channels == NULL) { | ||||
|         free(p); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return dc_ref(p); | ||||
| } | ||||
| 
 | ||||
| dc_guild_t dc_guild_from_json(json_t *j) | ||||
| { | ||||
|     dc_guild_t g = dc_guild_new(); | ||||
|     json_t *val = NULL; | ||||
|     json_t *c = NULL; | ||||
|     size_t idx = 0; | ||||
| 
 | ||||
|     val = json_object_get(j, "name"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     g->name = strdup(json_string_value(val)); | ||||
| 
 | ||||
|     val = json_object_get(j, "id"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     g->id = strdup(json_string_value(val)); | ||||
| 
 | ||||
|     /* there is a ton of more information here, that we should look
 | ||||
|      * add, including "member_count", "owner_id", but for channels | ||||
|      * will do nicely | ||||
|      */ | ||||
|     val = json_object_get(j, "channels"); | ||||
|     goto_if_true(val == NULL || !json_is_array(val), error); | ||||
| 
 | ||||
|     json_array_foreach(val, idx, c) { | ||||
|         dc_channel_t chan = dc_channel_from_json(c); | ||||
|         continue_if_true(chan == NULL); | ||||
|         g_ptr_array_add(g->channels, chan); | ||||
|     } | ||||
| 
 | ||||
|     return g; | ||||
| 
 | ||||
| error: | ||||
| 
 | ||||
|     dc_unref(g); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| size_t dc_guild_channels(dc_guild_t d) | ||||
| { | ||||
|     return_if_true(d == NULL || d->channels == NULL, 0); | ||||
|     return d->channels->len; | ||||
| } | ||||
| 
 | ||||
| dc_channel_t dc_guild_nth_channel(dc_guild_t d, size_t idx) | ||||
| { | ||||
|     return_if_true(d == NULL || d->channels == NULL, NULL); | ||||
|     return_if_true(idx >= d->channels->len, NULL); | ||||
|     return g_ptr_array_index(d->channels, idx); | ||||
| } | ||||
| 
 | ||||
| char const *dc_guild_name(dc_guild_t d) | ||||
| { | ||||
|     return_if_true(d == NULL, NULL); | ||||
|  | ||||
| @ -12,6 +12,7 @@ struct dc_session_ | ||||
| 
 | ||||
|     GHashTable *accounts; | ||||
|     GHashTable *channels; | ||||
|     GHashTable *guilds; | ||||
| }; | ||||
| 
 | ||||
| /* event handlers
 | ||||
| @ -40,6 +41,11 @@ static void dc_session_free(dc_session_t s) | ||||
|         s->channels = NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (s->guilds != NULL) { | ||||
|         g_hash_table_unref(s->guilds); | ||||
|         s->guilds = NULL; | ||||
|     } | ||||
| 
 | ||||
|     dc_session_logout(s); | ||||
| 
 | ||||
|     dc_unref(s->api); | ||||
| @ -79,6 +85,7 @@ static void dc_session_handle_ready(dc_session_t s, dc_event_t e) | ||||
|     size_t idx = 0; | ||||
|     json_t *c = NULL; | ||||
|     json_t *channels = NULL; | ||||
|     json_t *guilds = NULL; | ||||
| 
 | ||||
|     /* retrieve user information about ourselves, including snowflake,
 | ||||
|      * discriminator, and other things | ||||
| @ -127,6 +134,17 @@ static void dc_session_handle_ready(dc_session_t s, dc_event_t e) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* load guilds
 | ||||
|      */ | ||||
|     guilds = json_object_get(r, "guilds"); | ||||
|     if (guilds != NULL && json_is_array(guilds)) { | ||||
|         json_array_foreach(guilds, idx, c) { | ||||
|             dc_guild_t guild = dc_guild_from_json(c); | ||||
|             continue_if_true(guild == NULL); | ||||
|             dc_session_add_guild(s, guild); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* load channels
 | ||||
|      */ | ||||
|     channels = json_object_get(r, "private_channels"); | ||||
| @ -181,6 +199,11 @@ dc_session_t dc_session_new(dc_loop_t loop) | ||||
|         ); | ||||
|     goto_if_true(s->channels == NULL, error); | ||||
| 
 | ||||
|     s->guilds = g_hash_table_new_full(g_str_hash, g_str_equal, | ||||
|                                       free, dc_unref | ||||
|         ); | ||||
|     goto_if_true(s->channels == NULL, error); | ||||
| 
 | ||||
|     s->loop = dc_ref(loop); | ||||
| 
 | ||||
|     s->api = dc_api_new(); | ||||
| @ -394,3 +417,23 @@ dc_channel_t dc_session_channel_recipients(dc_session_t s, | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| GHashTable *dc_session_guilds(dc_session_t s) | ||||
| { | ||||
|     return_if_true(s == NULL, NULL); | ||||
|     return s->guilds; | ||||
| } | ||||
| 
 | ||||
| void dc_session_add_guild(dc_session_t s, dc_guild_t g) | ||||
| { | ||||
|     return_if_true(s == NULL || g == NULL,); | ||||
|     return_if_true(dc_guild_id(g) == NULL,); | ||||
| 
 | ||||
|     char const *id = dc_guild_id(g); | ||||
| 
 | ||||
|     if (!g_hash_table_contains(s->guilds, id)) { | ||||
|         g_hash_table_insert(s->guilds, strdup(id), dc_ref(g)); | ||||
|         /* TODO: dedup for saving storage
 | ||||
|          */ | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -13,6 +13,7 @@ SET(SOURCES | ||||
|   "include/ncdc/mainwindow.h" | ||||
|   "include/ncdc/ncdc.h" | ||||
|   "include/ncdc/textview.h" | ||||
|   "include/ncdc/treeview.h" | ||||
|   "src/ack.c" | ||||
|   "src/cmds.c" | ||||
|   "src/config.c" | ||||
| @ -26,6 +27,7 @@ SET(SOURCES | ||||
|   "src/ncdc.c" | ||||
|   "src/post.c" | ||||
|   "src/textview.c" | ||||
|   "src/treeview.c" | ||||
|   "src/util.c" | ||||
|   ) | ||||
| 
 | ||||
|  | ||||
| @ -24,4 +24,6 @@ void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n); | ||||
| void ncdc_mainwindow_rightview(ncdc_mainwindow_t n); | ||||
| void ncdc_mainwindow_leftview(ncdc_mainwindow_t n); | ||||
| 
 | ||||
| void ncdc_mainwindow_update_guilds(ncdc_mainwindow_t n); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										31
									
								
								ncdc/include/ncdc/treeview.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								ncdc/include/ncdc/treeview.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| #ifndef NCDC_TREEVIEW_H | ||||
| #define NCDC_TREEVIEW_H | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <ncdc/ncdc.h> | ||||
| 
 | ||||
| struct ncdc_treeitem_; | ||||
| typedef struct ncdc_treeitem_ *ncdc_treeitem_t; | ||||
| 
 | ||||
| ncdc_treeitem_t ncdc_treeitem_new(void); | ||||
| ncdc_treeitem_t ncdc_treeitem_new_string(wchar_t const *s); | ||||
| 
 | ||||
| wchar_t const *ncdc_treeitem_label(ncdc_treeitem_t i); | ||||
| void ncdc_treeitem_set_label(ncdc_treeitem_t i, wchar_t const *s); | ||||
| 
 | ||||
| void *ncdc_treeitem_tag(ncdc_treeitem_t i); | ||||
| void ncdc_treeitem_set_tag(ncdc_treeitem_t i, void *t); | ||||
| 
 | ||||
| void ncdc_treeitem_clear(ncdc_treeitem_t i); | ||||
| void ncdc_treeitem_add(ncdc_treeitem_t i, ncdc_treeitem_t c); | ||||
| void ncdc_treeitem_remove(ncdc_treeitem_t i, ncdc_treeitem_t c); | ||||
| 
 | ||||
| struct ncdc_treeview_; | ||||
| typedef struct ncdc_treeview_ *ncdc_treeview_t; | ||||
| 
 | ||||
| ncdc_treeview_t ncdc_treeview_new(void); | ||||
| ncdc_treeitem_t ncdc_treeview_root(ncdc_treeview_t t); | ||||
| void ncdc_treeview_render(ncdc_treeview_t t, WINDOW *w, int lines, int cols); | ||||
| 
 | ||||
| #endif | ||||
| @ -1,6 +1,7 @@ | ||||
| #include <ncdc/mainwindow.h> | ||||
| #include <ncdc/input.h> | ||||
| #include <ncdc/textview.h> | ||||
| #include <ncdc/treeview.h> | ||||
| #include <ncdc/cmds.h> | ||||
| #include <ncdc/ncdc.h> | ||||
| 
 | ||||
| @ -37,6 +38,8 @@ struct ncdc_mainwindow_ | ||||
|     WINDOW *sep2; | ||||
| 
 | ||||
|     ncdc_input_t in; | ||||
|     ncdc_treeview_t guildview; | ||||
|     ncdc_treeitem_t root; | ||||
| 
 | ||||
|     GPtrArray *views; | ||||
|     int curview; | ||||
| @ -62,6 +65,7 @@ static void ncdc_mainwindow_free(ncdc_mainwindow_t n) | ||||
|     delwin(n->sep2); | ||||
| 
 | ||||
|     dc_unref(n->in); | ||||
|     dc_unref(n->guildview); | ||||
| 
 | ||||
|     if (n->views != NULL) { | ||||
|         g_ptr_array_unref(n->views); | ||||
| @ -81,6 +85,9 @@ ncdc_mainwindow_t ncdc_mainwindow_new(void) | ||||
|     ptr->in = ncdc_input_new(); | ||||
|     ncdc_input_set_callback(ptr->in, ncdc_mainwindow_callback, ptr); | ||||
| 
 | ||||
|     ptr->guildview = ncdc_treeview_new(); | ||||
|     ptr->root = ncdc_treeview_root(ptr->guildview); | ||||
| 
 | ||||
|     ptr->views = g_ptr_array_new_with_free_func( | ||||
|         (GDestroyNotify)dc_unref | ||||
|         ); | ||||
| @ -134,7 +141,7 @@ ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s, | ||||
| static void ncdc_mainwindow_resize(ncdc_mainwindow_t n) | ||||
| { | ||||
|     n->guilds_h = LINES - 2; | ||||
|     n->guilds_w = (COLS / 5); | ||||
|     n->guilds_w = (COLS / 4); | ||||
|     n->guilds_y = 0; | ||||
|     n->guilds_x = 0; | ||||
| 
 | ||||
| @ -239,6 +246,85 @@ static void ncdc_mainwindow_render_status(ncdc_mainwindow_t n) | ||||
|     free(status); | ||||
| } | ||||
| 
 | ||||
| void ncdc_mainwindow_update_guilds(ncdc_mainwindow_t n) | ||||
| { | ||||
|     GHashTableIter iter; | ||||
|     gpointer key = NULL, value = NULL; | ||||
|     size_t idx = 0; | ||||
| 
 | ||||
|     ncdc_treeitem_clear(n->root); | ||||
| 
 | ||||
|     if (!is_logged_in()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     g_hash_table_iter_init(&iter, dc_session_guilds(current_session)); | ||||
|     while (g_hash_table_iter_next(&iter, &key, &value)) { | ||||
|         dc_guild_t g = (dc_guild_t)value; | ||||
|         ncdc_treeitem_t i = ncdc_treeitem_new(); | ||||
|         wchar_t *name = NULL; | ||||
| 
 | ||||
|         if (i == NULL) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         name = s_convert(dc_guild_name(g)); | ||||
|         if (name == NULL) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         ncdc_treeitem_set_label(i, name); | ||||
| 
 | ||||
|         free(name); | ||||
|         name = NULL; | ||||
| 
 | ||||
|         ncdc_treeitem_set_tag(i, g); | ||||
| 
 | ||||
|         /* add subchannels
 | ||||
|          */ | ||||
|         for (idx = 0; idx < dc_guild_channels(g); idx++) { | ||||
|             dc_channel_t c = dc_guild_nth_channel(g, idx); | ||||
|             ncdc_treeitem_t ci = NULL; | ||||
| 
 | ||||
|             if (dc_channel_name(c) == NULL || | ||||
|                 dc_channel_id(c) == NULL) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             /* skip categories, and shop channels
 | ||||
|              */ | ||||
|             if (dc_channel_type(c) == CHANNEL_TYPE_GUILD_CATEGORY || | ||||
|                 dc_channel_type(c) == CHANNEL_TYPE_GUILD_NEWS || | ||||
|                 dc_channel_type(c) == CHANNEL_TYPE_GUILD_STORE) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             ci = ncdc_treeitem_new(); | ||||
|             if (ci == NULL) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             aswprintf(&name, L"[%s] %s", | ||||
|                       (dc_channel_type(c) == CHANNEL_TYPE_GUILD_VOICE ? | ||||
|                        "<" : "#"), | ||||
|                       dc_channel_name(c) | ||||
|                 ); | ||||
|             if (name == NULL) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             ncdc_treeitem_set_label(ci, name); | ||||
|             free(name); | ||||
|             name = NULL; | ||||
| 
 | ||||
|             ncdc_treeitem_set_tag(ci, c); | ||||
|             ncdc_treeitem_add(i, ci); | ||||
|         } | ||||
| 
 | ||||
|         ncdc_treeitem_add(n->root, i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n) | ||||
| { | ||||
|     wint_t i = 0; | ||||
| @ -311,6 +397,8 @@ void ncdc_mainwindow_refresh(ncdc_mainwindow_t n) | ||||
| { | ||||
|     ncdc_textview_t v = 0; | ||||
| 
 | ||||
|     ncdc_mainwindow_update_guilds(n); | ||||
|     ncdc_treeview_render(n->guildview, n->guilds, n->guilds_h, n->guilds_w); | ||||
|     wnoutrefresh(n->guilds); | ||||
| 
 | ||||
|     /* render active text view
 | ||||
|  | ||||
							
								
								
									
										181
									
								
								ncdc/src/treeview.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								ncdc/src/treeview.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,181 @@ | ||||
| #include <ncdc/treeview.h> | ||||
| #include <ncdc/ncdc.h> | ||||
| 
 | ||||
| struct ncdc_treeitem_ | ||||
| { | ||||
|     dc_refable_t ref; | ||||
| 
 | ||||
|     /* content
 | ||||
|      */ | ||||
|     wchar_t *content; | ||||
| 
 | ||||
|     /* collapsed?
 | ||||
|      */ | ||||
|     bool collapsed; | ||||
| 
 | ||||
|     /* children
 | ||||
|      */ | ||||
|     GPtrArray *children; | ||||
| 
 | ||||
|     /* user defined data
 | ||||
|      */ | ||||
|     void *tag; | ||||
| }; | ||||
| 
 | ||||
| static void ncdc_treeitem_free(ncdc_treeitem_t t) | ||||
| { | ||||
|     return_if_true(t == NULL,); | ||||
| 
 | ||||
|     free(t->content); | ||||
|     t->content = NULL; | ||||
| 
 | ||||
|     if (t->children != NULL) { | ||||
|         g_ptr_array_unref(t->children); | ||||
|         t->children = NULL; | ||||
|     } | ||||
| 
 | ||||
|     free(t); | ||||
| } | ||||
| 
 | ||||
| ncdc_treeitem_t ncdc_treeitem_new(void) | ||||
| { | ||||
|     ncdc_treeitem_t t = calloc(1, sizeof(struct ncdc_treeitem_)); | ||||
|     return_if_true(t == NULL, NULL); | ||||
| 
 | ||||
|     t->ref.cleanup = (dc_cleanup_t)ncdc_treeitem_free; | ||||
| 
 | ||||
|     t->children = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref); | ||||
|     if (t->children == NULL) { | ||||
|         free(t); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return dc_ref(t); | ||||
| } | ||||
| 
 | ||||
| ncdc_treeitem_t ncdc_treeitem_new_string(wchar_t const *s) | ||||
| { | ||||
|     ncdc_treeitem_t t = ncdc_treeitem_new(); | ||||
|     return_if_true(t == NULL, NULL); | ||||
| 
 | ||||
|     t->content = wcsdup(s); | ||||
| 
 | ||||
|     return t; | ||||
| } | ||||
| 
 | ||||
| void ncdc_treeitem_add(ncdc_treeitem_t i, ncdc_treeitem_t c) | ||||
| { | ||||
|     return_if_true(i == NULL || c == NULL,); | ||||
|     g_ptr_array_add(i->children, dc_ref(c)); | ||||
| } | ||||
| 
 | ||||
| void ncdc_treeitem_remove(ncdc_treeitem_t i, ncdc_treeitem_t c) | ||||
| { | ||||
|     return_if_true(i == NULL || c == NULL,); | ||||
|     g_ptr_array_remove(i->children, c); | ||||
| } | ||||
| 
 | ||||
| void ncdc_treeitem_clear(ncdc_treeitem_t i) | ||||
| { | ||||
|     return_if_true(i == NULL || i->children == NULL,); | ||||
|     return_if_true(i->children->len == 0,); | ||||
|     g_ptr_array_remove_range(i->children, 0, i->children->len); | ||||
| } | ||||
| 
 | ||||
| void *ncdc_treeitem_tag(ncdc_treeitem_t i) | ||||
| { | ||||
|     return_if_true(i == NULL, NULL); | ||||
|     return i->tag; | ||||
| } | ||||
| 
 | ||||
| void ncdc_treeitem_set_tag(ncdc_treeitem_t i, void *t) | ||||
| { | ||||
|     return_if_true(i == NULL,); | ||||
|     i->tag = t; | ||||
| } | ||||
| 
 | ||||
| wchar_t const *ncdc_treeitem_label(ncdc_treeitem_t i) | ||||
| { | ||||
|     return_if_true(i == NULL, NULL); | ||||
|     return i->content; | ||||
| } | ||||
| 
 | ||||
| void ncdc_treeitem_set_label(ncdc_treeitem_t i, wchar_t const *s) | ||||
| { | ||||
|     return_if_true(i == NULL || s == NULL,); | ||||
|     free(i->content); | ||||
|     i->content = wcsdup(s); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ncdc_treeitem_render(ncdc_treeitem_t t, WINDOW *win, | ||||
|                      int lines, int cols, int l, int c) | ||||
| { | ||||
|     size_t i = 0, off = 0; | ||||
|     int ret = 0; | ||||
| 
 | ||||
|     if (t->content != NULL) { | ||||
|         size_t len = wcslen(t->content); | ||||
| 
 | ||||
|         mvwaddwstr(win, l, c, t->content); | ||||
|         off = ((len + c) / cols) + 1; | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < t->children->len; i++) { | ||||
|         ncdc_treeitem_t child = g_ptr_array_index(t->children, i); | ||||
|         ret = ncdc_treeitem_render(child, win, lines, cols, | ||||
|                                    l + off, c + 1 | ||||
|             ); | ||||
|         off += ret; | ||||
|     } | ||||
| 
 | ||||
|     return off; | ||||
| } | ||||
| 
 | ||||
| struct ncdc_treeview_ | ||||
| { | ||||
|     dc_refable_t ref; | ||||
| 
 | ||||
|     ncdc_treeitem_t root; | ||||
| }; | ||||
| 
 | ||||
| static void ncdc_treeview_free(ncdc_treeview_t t) | ||||
| { | ||||
|     return_if_true(t == NULL,); | ||||
| 
 | ||||
|     dc_unref(t->root); | ||||
|     t->root = NULL; | ||||
| 
 | ||||
|     free(t); | ||||
| } | ||||
| 
 | ||||
| ncdc_treeview_t ncdc_treeview_new(void) | ||||
| { | ||||
|     ncdc_treeview_t t = calloc(1, sizeof(struct ncdc_treeview_)); | ||||
|     return_if_true(t == NULL, NULL); | ||||
| 
 | ||||
|     t->ref.cleanup = (dc_cleanup_t)ncdc_treeview_free; | ||||
| 
 | ||||
|     t->root = ncdc_treeitem_new(); | ||||
|     goto_if_true(t->root == NULL, error); | ||||
| 
 | ||||
|     return dc_ref(t); | ||||
| 
 | ||||
| error: | ||||
| 
 | ||||
|     dc_unref(t); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void ncdc_treeview_render(ncdc_treeview_t t, WINDOW *w, int lines, int cols) | ||||
| { | ||||
|     werase(w); | ||||
|     wmove(w, 0, 0); | ||||
|     ncdc_treeitem_render(t->root, w, lines, cols, 0, 0); | ||||
| } | ||||
| 
 | ||||
| ncdc_treeitem_t ncdc_treeview_root(ncdc_treeview_t t) | ||||
| { | ||||
|     return_if_true(t == NULL, NULL); | ||||
|     return t->root; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user