409 lines
12 KiB
C
409 lines
12 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 *name, 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 *name, 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;
|
|
}
|
|
|
|
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;
|
|
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
|
|
GTK_POLICY_NEVER, 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,
|
|
"text", 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 void
|
|
on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id,
|
|
gchar const *name, 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.OnPlayerAdded: player %d "
|
|
"is already in the list, can't be added twice!", id);
|
|
return;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 *name, gchar const *sort, GmMcpUserlistView *view) {
|
|
GtkTreeIter iter;
|
|
|
|
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;
|
|
}
|
|
|
|
gtk_list_store_set(view->store, &iter, GM_USERLIST_NAME, name, -1);
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
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
|
|
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;
|
|
}
|