This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/mcp/gm-mcp-userlist-view.c

470 lines
13 KiB
C

#include <gtk/gtk.h>
#include "gm-mcp-package.h"
#include "gm-mcp-userlist-view.h"
#include "gm-iuserlist.h"
#include "widgets/gm-world-view.h"
#include "gm-pixbuf.h"
#include "gm-debug.h"
#define GM_USERLIST_ICON_SIZE 22
enum {
GM_USERLIST_ICON,
GM_USERLIST_NAME,
GM_USERLIST_ID,
GM_USERLIST_SORT,
GM_USERLIST_N_COLUMNS
};
typedef struct _GmMcpUserlistView {
GmWorldView *view;
GmMcpPackage *package;
GtkTreeModel *model;
GtkListStore *store;
GtkTreeView *tree_view;
GtkScrolledWindow *scrolled_window;
GtkWidget *popup_menu;
gboolean initializing;
} GmMcpUserlistView;
static void on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj);
static void on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id,
gchar const *icon, gchar const *sort,
GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id,
gchar const *sort, GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id,
gchar const *icon, gchar const *sort, GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id,
gchar const *icon, gchar const *sort, GmMcpUserlistView *view);
static gboolean on_gm_mcp_userlist_view_popup_menu(GtkWidget *widget,
GmMcpUserlistView *view);
static gboolean on_gm_mcp_userlist_view_button_press(GtkWidget *widget,
GdkEventButton *event, GmMcpUserlistView *view);
GtkTreeModel *
gm_mcp_userlist_view_model_create(GmMcpUserlistView *view) {
GtkListStore *store = gtk_list_store_new(GM_USERLIST_N_COLUMNS,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
GtkTreeModel *model = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(
store));
view->store = store;
view->model = model;
return model;
}
void
on_gm_mcp_userlist_view_style_set(GtkWidget *widget, GtkStyle *prev,
GmMcpUserlistView *view) {
pango_font_description_set_size(widget->style->font_desc, 8 * PANGO_SCALE);
}
GtkWidget *
gm_mcp_userlist_view_create_userlist(GmMcpUserlistView *view) {
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
GtkTreeModel *model = gm_mcp_userlist_view_model_create(view);
GtkWidget *tree_view = gtk_tree_view_new_with_model(model);
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
on_gm_mcp_userlist_view_style_set(tree_view, NULL, view);
g_signal_connect(tree_view, "style-set",
G_CALLBACK(on_gm_mcp_userlist_view_style_set), view);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_SHADOW_IN);
gtk_widget_set_size_request(scrolled_window, 150, -1);
gtk_widget_set_size_request(tree_view, 150, -1);
gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new_with_attributes(_("I"), renderer,
"pixbuf", GM_USERLIST_ICON, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
gtk_tree_view_column_set_min_width(column, 30);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
"markup", GM_USERLIST_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
GM_USERLIST_SORT, GTK_SORT_ASCENDING);
GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(tree_view), GTK_CAN_FOCUS);
gtk_widget_modify_base(GTK_WIDGET(tree_view), GTK_STATE_ACTIVE,
&(GTK_WIDGET(tree_view)->style->base[GTK_STATE_SELECTED]));
gtk_widget_modify_text(GTK_WIDGET(tree_view), GTK_STATE_ACTIVE,
&(GTK_WIDGET(tree_view)->style->text[GTK_STATE_SELECTED]));
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree_view));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
view->tree_view = GTK_TREE_VIEW(tree_view);
view->scrolled_window = GTK_SCROLLED_WINDOW(scrolled_window);
return scrolled_window;
}
void
gm_mcp_userlist_view_new(GmMcpPackage *package, GObject *parent) {
GmMcpUserlistView *view;
GtkPaned *paned;
GtkWidget *vbox, *child;
if (!GM_IS_WORLD_VIEW(parent)) {
return;
}
view = g_new0(GmMcpUserlistView, 1);
view->view = GM_WORLD_VIEW(parent);
view->package = package;
paned = GTK_PANED(gm_world_view_hpaned(view->view));
vbox = gtk_paned_get_child2(paned);
if (vbox == NULL) {
vbox = gtk_vbox_new(FALSE, 6);
gtk_paned_pack2(paned, vbox, FALSE, TRUE);
}
child = gm_mcp_userlist_view_create_userlist(view);
gtk_box_pack_end(GTK_BOX(vbox), child, TRUE, TRUE, 0);
gtk_widget_show_all(vbox);
g_signal_connect(view->tree_view, "popup-menu",
G_CALLBACK(on_gm_mcp_userlist_view_popup_menu), view);
g_signal_connect(view->tree_view, "button-press-event",
G_CALLBACK(on_gm_mcp_userlist_view_button_press), view);
g_signal_connect(package, "player_added",
G_CALLBACK(on_gm_mcp_userlist_view_player_added), view);
g_signal_connect(package, "player_removed",
G_CALLBACK(on_gm_mcp_userlist_view_player_removed), view);
g_signal_connect(package, "name_changed",
G_CALLBACK(on_gm_mcp_userlist_view_name_changed), view);
g_signal_connect(package, "state_changed",
G_CALLBACK(on_gm_mcp_userlist_view_state_changed), view);
g_signal_connect(package, "rank_changed",
G_CALLBACK(on_gm_mcp_userlist_view_rank_changed), view);
g_object_weak_ref(G_OBJECT(package), on_gm_mcp_userlist_view_weak_notify,
view);
}
/* Callbacks */
static void
on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj) {
GmMcpUserlistView *view = (GmMcpUserlistView *)(data);
GtkWidget *vbox;
GList *children;
if (GM_IS_WORLD_VIEW(view->view)) {
gtk_widget_destroy(GTK_WIDGET(view->scrolled_window));
vbox = gtk_paned_get_child2(GTK_PANED(gm_world_view_hpaned(
view->view)));
if (vbox != NULL) {
children = gtk_container_get_children(GTK_CONTAINER(vbox));
if (children == NULL) {
gtk_widget_destroy(vbox);
}
g_list_free(children);
}
}
g_free(data);
}
static gboolean
gm_mcp_userlist_view_find(GmMcpUserlistView *view, gint id, GtkTreeIter *iter) {
GtkTreeModel *model = GTK_TREE_MODEL(view->store);
gint iterid;
if (gtk_tree_model_get_iter_first(model, iter)) {
do {
gtk_tree_model_get(model, iter, GM_USERLIST_ID, &iterid, -1);
if (iterid == id) {
return TRUE;
}
} while (gtk_tree_model_iter_next(model, iter));
}
return FALSE;
}
static gchar *
gm_mcp_userlist_view_get_name(GmMcpUserlistView *view, GmMcpPackage *package,
gint id) {
gchar const *name;
gchar *status;
gchar *escape;
gchar *result;
gchar *color;
GdkColor col;
name = gm_iuserlist_get_name(GM_IUSERLIST(package), id);
if (!gm_iuserlist_supports_status(GM_IUSERLIST(package))) {
return g_strdup(name);
} else {
status = gm_iuserlist_get_status(GM_IUSERLIST(package), id);
if (status) {
col = GTK_WIDGET(view->tree_view)->style->text[GTK_STATE_INSENSITIVE];
color = g_strdup_printf("#%04X%04X%04X", col.red, col.green,
col.blue);
escape = g_markup_escape_text(status, -1);
result = g_strconcat(name, "\n<small><span color=\"", color, "\">",
escape, "</span></small>", NULL);
g_free(color);
g_free(status);
g_free(escape);
} else {
result = g_strdup(name);
}
return result;
}
}
static void
on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id,
gchar const *icon, gchar const *sort,
GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar *name;
if (gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnPlayerAdded: player %d "
"is already in the list, can't be added twice!", id);
return;
}
name = gm_mcp_userlist_view_get_name(view, package, id);
gtk_list_store_append(view->store, &iter);
gtk_list_store_set(view->store, &iter, GM_USERLIST_ID, id, GM_USERLIST_ICON,
gm_pixbuf_get_at_size(icon, GM_USERLIST_ICON_SIZE,
GM_USERLIST_ICON_SIZE), GM_USERLIST_NAME, name, GM_USERLIST_SORT,
sort, -1);
g_free(name);
}
static void
on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view) {
GtkTreeIter iter;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnPlayerRemoved: player %d "
"is not in the list, can't be removed!", id);
return;
}
gtk_list_store_remove(view->store, &iter);
}
static void
on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id,
gchar const *sort, GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar *name;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnNameChanged: player %d "
"is not in the list!", id);
return;
}
name = gm_mcp_userlist_view_get_name(view, package, id);
gtk_list_store_set(view->store, &iter, GM_USERLIST_NAME, name, -1);
g_free(name);
if (sort) {
gtk_list_store_set(view->store, &iter, GM_USERLIST_SORT, sort, -1);
}
}
static void
on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id,
gchar const *icon, gchar const *sort, GmMcpUserlistView *view) {
GtkTreeIter iter;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnRankChanged: player %d "
"is not in the list!", id);
return;
}
gtk_list_store_set(view->store, &iter, GM_USERLIST_ICON,
gm_pixbuf_get_at_size(icon, GM_USERLIST_ICON_SIZE,
GM_USERLIST_ICON_SIZE), -1);
if (sort) {
gtk_list_store_set(view->store, &iter, GM_USERLIST_SORT, sort, -1);
}
}
static void
on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id,
gchar const *icon, gchar const *sort, GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar *name;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnStateChanged: player %d "
"is not in the list!", id);
return;
}
name = gm_mcp_userlist_view_get_name(view, package, id);
gtk_list_store_set(view->store, &iter, GM_USERLIST_ICON,
gm_pixbuf_get_at_size(icon, GM_USERLIST_ICON_SIZE,
GM_USERLIST_ICON_SIZE), GM_USERLIST_NAME, name, -1);
g_free(name);
if (sort) {
gtk_list_store_set(view->store, &iter, GM_USERLIST_SORT, sort, -1);
}
}
static void
popup_menu_detach(GtkWidget *attach_widget, GtkMenu *menu) {
GmMcpUserlistView *view = (GmMcpUserlistView *)g_object_get_data(
G_OBJECT(menu), "McpUserlistView");
view->popup_menu = NULL;
}
static void
on_gm_mcp_userlist_view_menuitem_activate(GtkMenuItem *item,
GmMcpUserlistView *view) {
gchar *action = (gchar *)g_object_get_data(G_OBJECT(item),
"UserlistAction");
if (action) {
gm_world_sendln(GM_MCP_SESSION_WORLD(GM_MCP_PACKAGE_SESSION(
view->package)), action);
}
}
static gboolean
gm_mcp_userlist_view_do_popup(GmMcpUserlistView *view, GdkEventButton *event) {
GList *menu;
GList *item;
GmKeyValuePair *pair;
GtkWidget *menuitem;
GtkTreeSelection *selection = gtk_tree_view_get_selection(view->tree_view);
gint id;
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreePath *path;
if (!event) {
if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
return FALSE;
}
gtk_tree_model_get(model, &iter, GM_USERLIST_ID, &id, -1);
} else {
if (!gtk_tree_view_get_path_at_pos(view->tree_view, event->x, event->y,
&path, NULL, NULL, NULL)) {
return FALSE;
} else {
gtk_tree_model_get_iter(view->model, &iter, path);
gtk_tree_path_free(path);
gtk_tree_model_get(view->model, &iter, GM_USERLIST_ID, &id, -1);
}
}
menu = gm_iuserlist_get_menu(GM_IUSERLIST(view->package), id);
if (view->popup_menu) {
gtk_widget_destroy(view->popup_menu);
}
if (!menu) {
return FALSE;
}
view->popup_menu = gtk_menu_new();
g_object_set_data(G_OBJECT(view->popup_menu), "McpUserlistView", view);
gtk_menu_attach_to_widget(GTK_MENU(view->popup_menu),
GTK_WIDGET(view->tree_view), popup_menu_detach);
for (item = menu; item; item = item->next) {
pair = (GmKeyValuePair *)(item->data);
if (pair->key == NULL) {
menuitem = gtk_separator_menu_item_new();
g_free(pair->value);
} else {
menuitem = gtk_menu_item_new_with_mnemonic(pair->key);
g_object_set_data_full(G_OBJECT(menuitem), "UserlistAction",
pair->value, g_free);
g_signal_connect(menuitem, "activate",
G_CALLBACK(on_gm_mcp_userlist_view_menuitem_activate),
view);
}
gtk_widget_show(menuitem);
gtk_menu_shell_append(GTK_MENU_SHELL(view->popup_menu), menuitem);
g_free(pair->key);
g_free(pair);
}
g_list_free(menu);
if (!event) {
gtk_menu_popup(GTK_MENU(view->popup_menu), NULL, NULL, NULL, NULL, 0,
gtk_get_current_event_time());
} else {
gtk_menu_popup(GTK_MENU(view->popup_menu), NULL, NULL, NULL, NULL,
event->button, event->time);
}
return TRUE;
}
static gboolean
on_gm_mcp_userlist_view_popup_menu(GtkWidget *widget,
GmMcpUserlistView *view) {
return gm_mcp_userlist_view_do_popup(view, NULL);
}
static gboolean
on_gm_mcp_userlist_view_button_press(GtkWidget *widget, GdkEventButton *event,
GmMcpUserlistView *view) {
if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
gm_mcp_userlist_view_do_popup(view, event);
}
return FALSE;
}