Crossfire Client, Branch  R11627
spells.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_spells_c =
00002     "$Id: spells.c 9201 2008-06-01 17:32:45Z anmaster $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2006-2007 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire@metalforge.org
00023 */
00024 
00030 #ifdef HAVE_CONFIG_H
00031 #  include <config.h>
00032 #endif
00033 
00034 #include <gtk/gtk.h>
00035 #include <glade/glade.h>
00036 
00037 #include "client.h"
00038 
00039 #include "image.h"
00040 #include "gtk2proto.h"
00041 #include "metaserver.h"
00042 #include "main.h"
00043 
00044 enum Styles {
00045    Style_Attuned, Style_Repelled, Style_Denied, Style_Normal, Style_Last
00046 };
00047 
00048 static GtkWidget *spell_window, *spell_treeview, *spell_invoke, *spell_cast,
00049     *spell_options, *spell_label[Style_Last], *spell_eventbox[Style_Last];
00050 static GtkListStore    *spell_store;
00051 static GtkTreeSelection  *spell_selection;
00052 
00053 enum {LIST_IMAGE, LIST_NAME, LIST_LEVEL, LIST_TIME, LIST_COST,
00054     LIST_DAMAGE, LIST_SKILL, LIST_PATH, LIST_DESCRIPTION, LIST_BACKGROUND, LIST_MAX_SP, LIST_TAG,
00055     LIST_FOREGROUND, LIST_FONT};
00056 
00057 static const char *Style_Names[Style_Last] = {
00058     "spell_attuned", "spell_repelled", "spell_denied", "spell_normal"
00059 }; 
00061 static GtkStyle *spell_styles[Style_Last]; 
00063 static int has_init=0;
00064 
00072 void spell_get_styles(void)
00073 {
00074     int i;
00075     GtkStyle    *tmp_style;
00076     static int style_has_init=0;
00077 
00078     for (i=0; i < Style_Last; i++) {
00079         if (style_has_init && spell_styles[i]) g_object_unref(spell_styles[i]);
00080         tmp_style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL,
00081                                               Style_Names[i], G_TYPE_NONE);
00082         if (tmp_style) {
00083             spell_styles[i] = g_object_ref(tmp_style);
00084         }
00085         else {
00086             LOG(LOG_INFO, "spells.c::spell_get_styles", "Unable to find style for %s",
00087                 Style_Names[i]);
00088             spell_styles[i] = NULL;
00089         }
00090     }
00091     style_has_init=1;
00092 }
00093 
00104 static gboolean spell_selection_func (
00105                       GtkTreeSelection *selection,
00106                       GtkTreeModel     *model,
00107                       GtkTreePath      *path,
00108                       gboolean          path_currently_selected,
00109                       gpointer          userdata)
00110 {
00111     gtk_widget_set_sensitive(spell_invoke, TRUE);
00112     gtk_widget_set_sensitive(spell_cast, TRUE);
00113     return TRUE;
00114 }
00115 
00119 void update_spell_information(void)
00120 {
00121     Spell *spell;
00122     GtkTreeIter iter;
00123     char buf[MAX_BUF];
00124     GtkStyle    *row_style;
00125     PangoFontDescription    *font=NULL;
00126     GdkColor    *foreground=NULL, *background=NULL;
00127     int i;
00128 
00129     /* If the window/spellstore hasn't been created, return. */
00130     if (!has_init) return;
00131     cpl.spells_updated=0;
00132 
00133     /* We could try to do this in spell_get_styles, but if the window
00134      * isn't active, it won't work.  This is called whenever the window
00135      * is made active, so we know it will work, and the time
00136      * to set this info here, even though it may not change often,
00137      * is pretty trivial.
00138      */
00139     for (i=0; i < Style_Last; i++) {
00140         if (spell_styles[i]) {
00141             gtk_widget_modify_fg(spell_label[i],GTK_STATE_NORMAL,
00142                                  &spell_styles[i]->text[GTK_STATE_NORMAL]);
00143             gtk_widget_modify_font(spell_label[i], spell_styles[i]->font_desc);
00144             gtk_widget_modify_bg(spell_eventbox[i],GTK_STATE_NORMAL,
00145                                  &spell_styles[i]->base[GTK_STATE_NORMAL]);
00146         } else {
00147             gtk_widget_modify_fg(spell_label[i],GTK_STATE_NORMAL, NULL);
00148             gtk_widget_modify_font(spell_label[i], NULL);
00149             gtk_widget_modify_bg(spell_eventbox[i],GTK_STATE_NORMAL, NULL);
00150         }
00151     }
00152 
00153     gtk_list_store_clear(spell_store);
00154     for (spell = cpl.spelldata; spell; spell=spell->next) {
00155         gtk_list_store_append(spell_store, &iter);
00156 
00157         buf[0] = 0;
00158         if (spell->sp) snprintf(buf, sizeof(buf), "%d Mana ", spell->sp);
00159         if (spell->grace) snprintf(buf + strlen(buf), sizeof(buf)-strlen(buf), "%d Grace", spell->grace);
00160 
00161         if (spell->path & cpl.stats.denied) { row_style = spell_styles[Style_Denied]; }
00162         else if (spell->path & cpl.stats.repelled) { row_style = spell_styles[Style_Repelled]; }
00163         else if (spell->path & cpl.stats.attuned) { row_style = spell_styles[Style_Attuned]; }
00164         else row_style = spell_styles[Style_Normal];
00165 
00166         if (row_style) {
00167             foreground = &row_style->text[GTK_STATE_NORMAL];
00168             background = &row_style->base[GTK_STATE_NORMAL];
00169             font = row_style->font_desc;
00170         } else {
00171             foreground=NULL;
00172             background=NULL;
00173             font=NULL;
00174         }
00175 
00176         gtk_list_store_set(spell_store, &iter,
00177                            LIST_NAME, spell->name,
00178                            LIST_LEVEL, spell->level,
00179                            LIST_COST, buf,
00180                            LIST_DAMAGE, spell->dam,
00181                            LIST_SKILL, spell->skill,
00182                            LIST_DESCRIPTION, spell->message,
00183                            LIST_BACKGROUND, background,
00184                            LIST_FOREGROUND, foreground,
00185                            LIST_FONT, font,
00186                            LIST_MAX_SP, (spell->sp > spell->grace)?spell->sp:spell->grace,
00187                            LIST_TAG, spell->tag,
00188                            -1);
00189     }
00190 }
00191 
00197 void
00198 on_spells_activate                     (GtkMenuItem     *menuitem,
00199                                         gpointer         user_data)
00200 {
00201     GladeXML *xml_tree;
00202     GtkWidget *widget;
00203 
00204     if (!has_init) {
00205         GtkCellRenderer *renderer;
00206         GtkTreeViewColumn *column;
00207 
00208         spell_window = glade_xml_get_widget(dialog_xml, "spell_window");
00209         xml_tree = glade_get_widget_tree(GTK_WIDGET(spell_window));
00210 
00211         spell_invoke = glade_xml_get_widget(xml_tree,"spell_invoke");
00212         spell_cast = glade_xml_get_widget(xml_tree,"spell_cast");
00213         spell_options = glade_xml_get_widget(xml_tree,"spell_options");
00214         spell_treeview = glade_xml_get_widget(xml_tree, "spell_treeview");
00215 
00216         g_signal_connect ((gpointer) spell_treeview, "row_activated",
00217             G_CALLBACK (on_spell_treeview_row_activated), NULL);
00218         g_signal_connect ((gpointer) spell_cast, "clicked",
00219             G_CALLBACK (on_spell_cast_clicked), NULL);
00220         g_signal_connect ((gpointer) spell_invoke, "clicked",
00221             G_CALLBACK (on_spell_invoke_clicked), NULL);
00222 
00223         widget = glade_xml_get_widget(xml_tree, "spell_close");
00224         g_signal_connect ((gpointer) widget, "clicked",
00225             G_CALLBACK (on_spell_close_clicked), NULL);
00226 
00227         spell_store = gtk_list_store_new(14,
00228                                 G_TYPE_OBJECT,  /* Image - not used */
00229                                 G_TYPE_STRING,  /* Name */
00230                                 G_TYPE_INT,     /* Level */
00231                                 G_TYPE_INT,     /* Time */
00232                                 G_TYPE_STRING,  /* SP/Grace */
00233                                 G_TYPE_INT,     /* Damage */
00234                                 G_TYPE_STRING,  /* Skill name */
00235                                 G_TYPE_INT,     /* Spell path */
00236                                 G_TYPE_STRING,  /* Description */
00237                                 GDK_TYPE_COLOR, /* Change the background color of the entry */
00238                                 G_TYPE_INT,
00239                                 G_TYPE_INT,
00240                                 GDK_TYPE_COLOR,
00241                                 PANGO_TYPE_FONT_DESCRIPTION
00242                               );
00243 
00244         gtk_tree_view_set_model(GTK_TREE_VIEW(spell_treeview), GTK_TREE_MODEL(spell_store));
00245         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spell_treeview), TRUE);
00246 
00247         /* Note it is intentional we don't show (render) some fields:
00248          * image - we don't have images right now it seems.
00249          * time - not sure if it worth the space.
00250          * spell path - done by color
00251          */
00252         renderer = gtk_cell_renderer_text_new ();
00253         column = gtk_tree_view_column_new_with_attributes ("Spell", renderer,
00254                                                 "text", LIST_NAME,
00255                                                 NULL);
00256         gtk_tree_view_append_column (GTK_TREE_VIEW (spell_treeview), column);
00257         gtk_tree_view_column_set_sort_column_id(column, LIST_NAME);
00258         gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
00259         gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
00260         gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
00261 
00262         renderer = gtk_cell_renderer_text_new ();
00263         column = gtk_tree_view_column_new_with_attributes ("Level", renderer,
00264                                                 "text", LIST_LEVEL,
00265                                                 NULL);
00266         gtk_tree_view_append_column (GTK_TREE_VIEW (spell_treeview), column);
00267         gtk_tree_view_column_set_sort_column_id(column, LIST_LEVEL);
00268         gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
00269         gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
00270         gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
00271 
00272         renderer = gtk_cell_renderer_text_new ();
00273         column = gtk_tree_view_column_new_with_attributes ("SP/Mana Cost", renderer,
00274                                                 "text", LIST_COST,
00275                                                 NULL);
00276         gtk_tree_view_append_column (GTK_TREE_VIEW (spell_treeview), column);
00277 
00278         /* since this is a string column, it would do a string sort.  Instead,
00279          * we set up a int column and tie this column to sort on that.
00280          */
00281         gtk_tree_view_column_set_sort_column_id(column, LIST_MAX_SP);
00282         gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
00283         gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
00284         gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
00285 
00286         renderer = gtk_cell_renderer_text_new ();
00287         column = gtk_tree_view_column_new_with_attributes ("Damage", renderer,
00288                                                 "text", LIST_DAMAGE,
00289                                                 NULL);
00290         gtk_tree_view_append_column (GTK_TREE_VIEW (spell_treeview), column);
00291         gtk_tree_view_column_set_sort_column_id(column, LIST_DAMAGE);
00292         gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
00293         gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
00294         gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
00295 
00296         column = gtk_tree_view_column_new_with_attributes ("Skill", renderer,
00297                                                 "text", LIST_SKILL,
00298                                                 NULL);
00299         gtk_tree_view_append_column (GTK_TREE_VIEW (spell_treeview), column);
00300         gtk_tree_view_column_set_sort_column_id(column, LIST_SKILL);
00301         gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
00302         gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
00303         gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
00304 
00305         renderer = gtk_cell_renderer_text_new ();
00306         column = gtk_tree_view_column_new_with_attributes ("Description", renderer,
00307                                                 "text", LIST_DESCRIPTION,
00308                                                 NULL);
00309         gtk_tree_view_append_column (GTK_TREE_VIEW (spell_treeview), column);
00310         gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
00311         gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
00312         gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
00313 
00314         spell_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(spell_treeview));
00315         gtk_tree_selection_set_mode (spell_selection, GTK_SELECTION_BROWSE);
00316         gtk_tree_selection_set_select_function(spell_selection, spell_selection_func,
00317                                                NULL, NULL);
00318 
00319 
00320         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(spell_store),
00321                                              LIST_NAME,
00322                                              GTK_SORT_ASCENDING);
00323 
00324         /* the style code will set the colors for these */
00325         spell_label[Style_Attuned] =
00326             glade_xml_get_widget(xml_tree, "spell_label_attuned");
00327         spell_label[Style_Repelled] =
00328             glade_xml_get_widget(xml_tree, "spell_label_repelled");
00329         spell_label[Style_Denied] =
00330             glade_xml_get_widget(xml_tree, "spell_label_denied");
00331         spell_label[Style_Normal] =
00332             glade_xml_get_widget(xml_tree, "spell_label_normal");
00333 
00334         /* We use eventboxes because the label widget is a transparent widget -
00335          * we can't set the background in it and have it work.
00336          * But we can set the background in the event box, and put the label
00337          * widget in the eventbox.
00338          */
00339         spell_eventbox[Style_Attuned] =
00340             glade_xml_get_widget(xml_tree, "spell_eventbox_attuned");
00341         spell_eventbox[Style_Repelled] =
00342             glade_xml_get_widget(xml_tree, "spell_eventbox_repelled");
00343         spell_eventbox[Style_Denied] =
00344             glade_xml_get_widget(xml_tree, "spell_eventbox_denied");
00345         spell_eventbox[Style_Normal] =
00346             glade_xml_get_widget(xml_tree, "spell_eventbox_normal");
00347     }
00348     gtk_widget_set_sensitive(spell_invoke, FALSE);
00349     gtk_widget_set_sensitive(spell_cast, FALSE);
00350     gtk_widget_show(spell_window);
00351     spell_get_styles();
00352 
00353     has_init=1;
00354     /* has to be called after has_init is set to 1 */
00355     update_spell_information();
00356 
00357 }
00358 
00366 void
00367 on_spell_treeview_row_activated        (GtkTreeView     *treeview,
00368                                         GtkTreePath     *path,
00369                                         GtkTreeViewColumn *column,
00370                                         gpointer         user_data)
00371 {
00372     GtkTreeIter iter;
00373     GtkTreeModel    *model;
00374     int tag;
00375     char    command[MAX_BUF];
00376     const char *options = NULL;
00377 
00378     model = gtk_tree_view_get_model(treeview);
00379     if (gtk_tree_model_get_iter(model, &iter, path)) {
00380         gtk_tree_model_get(model, &iter, LIST_TAG, &tag, -1);
00381 
00382         if (!tag) {
00383             LOG(LOG_ERROR,"spells.c:on_spell_cast_clicked", "Unable to get spell tag\n");
00384             return;
00385         }
00386         snprintf(command, MAX_BUF-1, "cast %d %s", tag, options);
00387         send_command(command, -1, 1);
00388     }
00389 }
00390 
00396 void
00397 on_spell_cast_clicked                  (GtkButton       *button,
00398                                         gpointer         user_data)
00399 {
00400     const char *options = NULL;
00401     char    command[MAX_BUF];
00402     GtkTreeIter iter;
00403     GtkTreeModel    *model;
00404     int tag;
00405 
00406     options = gtk_entry_get_text(GTK_ENTRY(spell_options));
00407 
00408     if (gtk_tree_selection_get_selected (spell_selection, &model, &iter)) {
00409         gtk_tree_model_get(model, &iter, LIST_TAG, &tag, -1);
00410 
00411         if (!tag) {
00412             LOG(LOG_ERROR,"spells.c:on_spell_cast_clicked", "Unable to get spell tag\n");
00413             return;
00414         }
00415         snprintf(command, MAX_BUF-1, "cast %d %s", tag, options);
00416         send_command(command, -1, 1);
00417     }
00418 
00419 }
00420 
00426 void
00427 on_spell_invoke_clicked                 (GtkButton       *button,
00428                                         gpointer         user_data)
00429 {
00430     const char *options = NULL;
00431     char    command[MAX_BUF];
00432     GtkTreeIter iter;
00433     GtkTreeModel    *model;
00434     int tag;
00435 
00436     options = gtk_entry_get_text(GTK_ENTRY(spell_options));
00437 
00438     if (gtk_tree_selection_get_selected (spell_selection, &model, &iter)) {
00439         gtk_tree_model_get(model, &iter, LIST_TAG, &tag, -1);
00440 
00441         if (!tag) {
00442             LOG(LOG_ERROR,"spells.c:on_spell_invoke_clicked", "Unable to get spell tag\n");
00443             return;
00444         }
00445         snprintf(command, MAX_BUF-1, "invoke %d %s", tag, options);
00446         send_command(command, -1, 1);
00447     }
00448 }
00449 
00455 void
00456 on_spell_close_clicked                 (GtkButton       *button,
00457                                         gpointer         user_data)
00458 {
00459     gtk_widget_hide(spell_window);
00460 
00461 }