locator.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2001-2002 The Exult Team
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include "studio.h"
00030 #include "servemsg.h"
00031 #include "exult_constants.h"
00032 #include "locator.h"
00033 #include "utils.h"
00034 
00035 using std::cout;
00036 using std::endl;
00037 
00038 /*
00039  *  Open locator window.
00040  */
00041 
00042 C_EXPORT void on_locator1_activate
00043   (
00044   GtkMenuItem     *menuitem,
00045         gpointer         user_data
00046   )
00047   {
00048   ExultStudio *studio = ExultStudio::get_instance();
00049   studio->open_locator_window();
00050   }
00051 void ExultStudio::open_locator_window
00052   (
00053   )
00054   {
00055   if (!locwin)      // First time?
00056     {
00057     locwin = new Locator();
00058     }
00059   locwin->show(true);
00060   }
00061 
00062 /*
00063  *  Locator window's close button.
00064  */
00065 C_EXPORT void on_loc_close_clicked
00066   (
00067   GtkButton *btn,
00068   gpointer user_data
00069   )
00070   {
00071   Locator *loc = (Locator *) gtk_object_get_user_data(
00072       GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(btn))));
00073   loc->show(false);
00074   }
00075 
00076 /*
00077  *  Locator window's X button.
00078  */
00079 C_EXPORT gboolean on_loc_window_delete_event
00080   (
00081   GtkWidget *widget,
00082   GdkEvent *event,
00083   gpointer user_data
00084   )
00085   {
00086   Locator *loc = (Locator *) 
00087         gtk_object_get_user_data(GTK_OBJECT(widget));
00088   loc->show(false);
00089   return TRUE;
00090   }
00091 
00092 /*
00093  *  Draw area created, or size changed.
00094  */
00095 C_EXPORT gint on_loc_draw_configure_event
00096   (
00097   GtkWidget *widget,    // The view window.
00098   GdkEventConfigure *event,
00099   gpointer data     // ->Shape_chooser
00100   )
00101   {
00102   Locator *loc = (Locator *) gtk_object_get_user_data(
00103     GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(widget))));
00104   loc->configure(widget);
00105   return TRUE;
00106   }
00107 /*
00108  *  Draw area needs a repain.
00109  */
00110 C_EXPORT gint on_loc_draw_expose_event
00111   (
00112   GtkWidget *widget,    // The view window.
00113   GdkEventExpose *event,
00114   gpointer data     // ->Shape_chooser.
00115   )
00116   {
00117   Locator *loc = (Locator *) gtk_object_get_user_data(
00118     GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(widget))));
00119   loc->render(&event->area);
00120   return TRUE;
00121   }
00122 /*
00123  *  Mouse events in draw area.
00124  */
00125 C_EXPORT gint on_loc_draw_button_press_event
00126   (
00127   GtkWidget *widget,    // The view window.
00128   GdkEventButton *event,
00129   gpointer data     // ->Chunk_chooser.
00130   )
00131   {
00132   Locator *loc = (Locator *) gtk_object_get_user_data(
00133     GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(widget))));
00134   return loc->mouse_press(event);
00135   }
00136 
00137 C_EXPORT gint on_loc_draw_button_release_event
00138   (
00139   GtkWidget *widget,    // The view window.
00140   GdkEventButton *event,
00141   gpointer data     // ->Chunk_chooser.
00142   )
00143   {
00144   Locator *loc = (Locator *) gtk_object_get_user_data(
00145     GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(widget))));
00146   return loc->mouse_release(event);
00147   }
00148 
00149 C_EXPORT gint on_loc_draw_motion_notify_event
00150   (
00151   GtkWidget *widget,    // The view window.
00152   GdkEventMotion *event,
00153   gpointer data     // ->Chunk_chooser.
00154   )
00155   {
00156   Locator *loc = (Locator *) gtk_object_get_user_data(
00157     GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(widget))));
00158   return loc->mouse_motion(event);
00159   }
00160 
00161 /*
00162  *  Create locator window.
00163  */
00164 
00165 Locator::Locator
00166   (
00167   ) : drawgc(0), tx(0), ty(0), txs(40), tys(25), scale(1),
00168       dragging(false), send_location_timer(-1)
00169   {
00170   GladeXML *app_xml = ExultStudio::get_instance()->get_xml();
00171   win = glade_xml_get_widget(app_xml, "loc_window");
00172   gtk_object_set_user_data(GTK_OBJECT(win), this);
00173   draw = glade_xml_get_widget(app_xml, "loc_draw");
00174           // Indicate the events we want.
00175   gtk_widget_set_events(draw, GDK_EXPOSURE_MASK | 
00176     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
00177     GDK_BUTTON1_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
00178           // Set up scales.
00179   GtkWidget *scale = glade_xml_get_widget(app_xml, "loc_hscale");
00180   hadj = gtk_range_get_adjustment(GTK_RANGE(scale));
00181   scale = glade_xml_get_widget(app_xml, "loc_vscale");
00182   vadj = gtk_range_get_adjustment(GTK_RANGE(scale));
00183   hadj->upper = vadj->upper = c_num_chunks;
00184   hadj->page_increment = vadj->page_increment = c_chunks_per_schunk;
00185   hadj->page_size = vadj->page_size = 2;
00186   gtk_signal_emit_by_name(GTK_OBJECT(hadj), "changed");
00187   gtk_signal_emit_by_name(GTK_OBJECT(vadj), "changed");
00188           // Set scrollbar handlers.
00189   gtk_signal_connect(GTK_OBJECT(hadj), "value_changed",
00190           GTK_SIGNAL_FUNC(hscrolled), this);
00191   gtk_signal_connect(GTK_OBJECT(vadj), "value_changed",
00192           GTK_SIGNAL_FUNC(vscrolled), this);
00193   }
00194 
00195 /*
00196  *  Delete.
00197  */
00198 
00199 Locator::~Locator
00200   (
00201   )
00202   {
00203   if (send_location_timer != -1)
00204     gtk_timeout_remove(send_location_timer);
00205   gtk_widget_destroy(win);
00206   }
00207 
00208 /*
00209  *  Show/hide.
00210  */
00211 
00212 void Locator::show
00213   (
00214   bool tf
00215   )
00216   {
00217   if (tf)
00218     {
00219     gtk_widget_show(win);
00220     query_location(); // Get Exult's loc.
00221     }
00222   else
00223     gtk_widget_hide(win);
00224   }
00225 
00226 /*
00227  *  Configure the draw window.
00228  */
00229 
00230 void Locator::configure
00231   (
00232   GtkWidget *widget   // The draw window.
00233   )
00234   {
00235   if (!widget->window)
00236     return;     // Not ready yet.
00237   if (!drawgc)      // First time?
00238     {
00239     drawgc = gdk_gc_new(widget->window);
00240     }
00241   }
00242 
00243 /*
00244  *  Display.
00245  */
00246 
00247 void Locator::render
00248   (
00249   GdkRectangle *area    // 0 for whole draw area.
00250   )
00251   {
00252           // Get dims.
00253   int draww = draw->allocation.width,
00254       drawh = draw->allocation.height;
00255   GdkRectangle all;
00256   if (!area)
00257     {
00258     all.x = all.y = 0;
00259     all.width = draww;
00260     all.height = drawh;
00261     area = &all;
00262     }
00263   gdk_gc_set_clip_rectangle(drawgc, area);
00264           // Background is dark blue.
00265   gdk_rgb_gc_set_foreground(drawgc, 64);
00266   gdk_draw_rectangle(draw->window, drawgc, TRUE, area->x, area->y,
00267           area->width, area->height);
00268           // Show superchunks with dotted lines.
00269 #if 0
00270   gdk_gc_set_line_attributes(drawgc, 1, GDK_LINE_ON_OFF_DASH, 
00271           GDK_CAP_BUTT, GDK_JOIN_BEVEL);
00272 #endif
00273           // Paint in light grey.
00274   gdk_rgb_gc_set_foreground(drawgc, 0xc0c0c0);
00275   int i;
00276   int cur = 0;      // Cur. pixel.
00277           // First the rows.
00278   for (i = 0; i < c_num_schunks - 1; i++)
00279     {
00280     int rowht = (drawh - cur)/(c_num_schunks - i);
00281     cur += rowht;
00282     gdk_draw_line(draw->window, drawgc, 0, cur, draww, cur);
00283     if (i == c_num_schunks/2 - 1)
00284       {   // Make middle one 3 pixels.
00285       gdk_draw_line(draw->window, drawgc, 0, cur - 1, 
00286               draww, cur - 1);
00287       gdk_draw_line(draw->window, drawgc, 0, cur + 1, 
00288               draww, cur + 1);
00289       }
00290     }
00291   cur = 0;      // Now the columns.
00292   for (i = 0; i < c_num_schunks - 1; i++)
00293     {
00294     int colwd = (draww - cur)/(c_num_schunks - i);
00295     cur += colwd;
00296     gdk_draw_line(draw->window, drawgc, cur, 0, cur, drawh);
00297     if (i == c_num_schunks/2 - 1)
00298       {   // Make middle one 3 pixels.
00299       gdk_draw_line(draw->window, drawgc, cur - 1, 0, 
00300               cur - 1, drawh);
00301       gdk_draw_line(draw->window, drawgc, cur + 1, 0, 
00302               cur + 1, drawh);
00303       }
00304     }
00305 #if 0
00306           // Back to solid lines for loc. box.
00307   gdk_gc_set_line_attributes(drawgc, 1, GDK_LINE_SOLID, 
00308           GDK_CAP_BUTT, GDK_JOIN_BEVEL);
00309 #endif
00310           // Figure where to draw box.
00311   int cx = tx/c_tiles_per_chunk, cy = ty/c_tiles_per_chunk;
00312   int x = (cx*draww)/c_num_chunks,
00313       y = (cy*drawh)/c_num_chunks;
00314   int w = (txs*draww)/c_num_tiles,
00315       h = (tys*drawh)/c_num_tiles;
00316   if (w == 0)
00317     w = 1;
00318   if (h == 0)
00319     h = 1;
00320           // Draw location in yellow.
00321   gdk_rgb_gc_set_foreground(drawgc, (255<<16) + (255<<8));
00322   gdk_draw_rectangle(draw->window, drawgc, FALSE, x, y, w, h);
00323   viewbox.x = x; viewbox.y = y; // Save location.
00324   viewbox.width = w; viewbox.height = h;
00325           // Put a light-red box around it.
00326   gdk_rgb_gc_set_foreground(drawgc, (255<<16) + (128<<8) + 128);
00327   gdk_draw_rectangle(draw->window, drawgc, FALSE, 
00328           x - 3, y - 3, w + 6, h + 6);
00329   }
00330 
00331 /*
00332  *  Message was received from Exult that the view has changed.
00333  */
00334 
00335 void Locator::view_changed
00336   (
00337   unsigned char *data,    // Tx, Ty, xtiles, ytiles, scale.
00338   int datalen
00339   )
00340   {
00341   if (datalen < 4*4)
00342     return;     // Bad length.
00343   if (dragging)
00344     return;   //+++++++Not sure about this.
00345   tx = Read4(data);
00346   ty = Read4(data);
00347   txs = Read4(data);
00348   tys = Read4(data);
00349           // ++++Scale?  Later.
00350           // Do things by chunk.
00351   int cx = tx/c_tiles_per_chunk, cy = ty/c_tiles_per_chunk;
00352   tx = cx*c_tiles_per_chunk;
00353   ty = cy*c_tiles_per_chunk;
00354           // Update scrolls.
00355   gtk_adjustment_set_value(hadj, cx);
00356   gtk_adjustment_set_value(vadj, cy);
00357   render();
00358   }
00359 
00360 /*
00361  *  Handle a scrollbar event.
00362  */
00363 
00364 void Locator::vscrolled     // For vertical scrollbar.
00365   (
00366   GtkAdjustment *adj,   // The adjustment.
00367   gpointer data     // ->Shape_chooser.
00368   )
00369   {
00370   Locator *loc = (Locator *) data;
00371   int oldty = loc->ty;
00372   loc->ty = ((gint) adj->value)*c_tiles_per_chunk;
00373   if (loc->ty != oldty)   // (Already equal if this event came
00374           //   from Exult msg.).
00375     {
00376     loc->render();
00377     loc->send_location();
00378     }
00379   }
00380 void Locator::hscrolled     // For horizontal scrollbar.
00381   (
00382   GtkAdjustment *adj,   // The adjustment.
00383   gpointer data     // ->Locator.
00384   )
00385   {
00386   Locator *loc = (Locator *) data;
00387   int oldtx = loc->tx;
00388   loc->tx = ((gint) adj->value)*c_tiles_per_chunk;
00389   if (loc->tx != oldtx)   // (Already equal if this event came
00390           //   from Exult msg.).
00391     {
00392     loc->render();
00393     loc->send_location();
00394     }
00395   }
00396 
00397 /*
00398  *  Send location to Exult.
00399  */
00400 
00401 void Locator::send_location
00402   (
00403   )
00404   {
00405   unsigned char data[50];
00406   unsigned char *ptr = &data[0];
00407   Write4(ptr, tx);
00408   Write4(ptr, ty);
00409   Write4(ptr, txs);
00410   Write4(ptr, tys);
00411   Write4(ptr, static_cast<uint32>(-1));   // Don't change.
00412   cout << "Locator::send_location" << endl;
00413   ExultStudio::get_instance()->send_to_server(Exult_server::view_pos,
00414           &data[0], ptr - data);
00415   }
00416 
00417 /*
00418  *  Query Exult for its location.
00419  */
00420 
00421 void Locator::query_location
00422   (
00423   )
00424   {
00425   unsigned char data[50];
00426   unsigned char *ptr = &data[0];
00427   Write4(ptr, static_cast<uint32>(-1));
00428   Write4(ptr, static_cast<uint32>(-1));
00429   Write4(ptr, static_cast<uint32>(-1));
00430   Write4(ptr, static_cast<uint32>(-1));
00431   Write4(ptr, static_cast<uint32>(-1));
00432   ExultStudio::get_instance()->send_to_server(Exult_server::view_pos,
00433           &data[0], ptr - data);
00434   }
00435 
00436 /*
00437  *  This is called a fraction of a second after mouse motion to send
00438  *  the new location to Exult if the mouse hasn't moved further.
00439  */
00440 
00441 gint Locator::delayed_send_location
00442   (
00443   gpointer data     // ->locator.
00444   )
00445   {
00446   Locator *loc = (Locator *) data;
00447   loc->send_location();
00448   loc->send_location_timer = -1;
00449   return 0;     // Cancels timer.
00450   }
00451 
00452 /*
00453  *  Go to a mouse location in the draw area.
00454  */
00455 
00456 void Locator::goto_mouse
00457   (
00458   int mx, int my,     // Pixel coords. in draw area.
00459   bool delay_send     // Delay send_location for a bit.
00460   )
00461   {
00462   GdkRectangle oldbox = viewbox;  // Old location of box.
00463   int oldtx = tx, oldty = ty;
00464           // Set tx,ty here so hscrolled() &
00465           //   vscrolled() don't send to Exult.
00466   tx = (mx*c_num_tiles)/draw->allocation.width;
00467   ty = (my*c_num_tiles)/draw->allocation.height;
00468   int cx = tx/c_tiles_per_chunk, cy = ty/c_tiles_per_chunk;
00469   if (cx > c_num_chunks - 2)
00470     cx = c_num_chunks - 2;
00471   if (cy > c_num_chunks - 2)
00472     cy = c_num_chunks - 2;
00473   tx = cx*c_tiles_per_chunk;
00474   ty = cy*c_tiles_per_chunk;
00475           // Update scrolls.
00476   gtk_adjustment_set_value(hadj, cx);
00477   gtk_adjustment_set_value(vadj, cy);
00478           // Now we just send it once.
00479   if (tx != oldtx || ty != oldty)
00480     {
00481     if (send_location_timer != -1)
00482       gtk_timeout_remove(send_location_timer);
00483     if (delay_send)   // Send in 1/3 sec. if no more motion.
00484       send_location_timer = gtk_timeout_add(333, 
00485           delayed_send_location, this);
00486     else
00487       {
00488       send_location();
00489       send_location_timer = -1;
00490       }
00491     GdkRectangle newbox;  // Figure dirty rectangle;
00492     GdkRectangle dirty;
00493     newbox.x = (cx*draw->allocation.width)/c_num_chunks,
00494         newbox.y = (cy*draw->allocation.height)/c_num_chunks;
00495     newbox.width = oldbox.width;
00496     newbox.height = oldbox.height;
00497     gdk_rectangle_union(&oldbox, &newbox, &dirty);
00498           // Expand a bit.
00499     dirty.x -= 4; dirty.y -= 4; 
00500     dirty.width += 8; dirty.height += 8;
00501     render(&dirty);
00502     }
00503   }
00504 
00505 /*
00506  *  Handle a mouse-press event.
00507  */
00508 
00509 gint Locator::mouse_press
00510   (
00511   GdkEventButton *event
00512   )
00513   {
00514   dragging = false;
00515   if (event->button != 1)
00516     return FALSE;   // Handling left-click.
00517           // Get mouse position, draw dims.
00518   int mx = (int) event->x, my = (int) event->y;
00519   int draww = draw->allocation.width,
00520       drawh = draw->allocation.height;
00521           // Double-click?
00522   if (((GdkEvent *) event)->type == GDK_2BUTTON_PRESS)
00523     {
00524     goto_mouse(mx, my);
00525     return TRUE;
00526     }
00527           // On (or close to) view box?
00528   if (mx < viewbox.x - 3 || my < viewbox.y - 3 ||
00529       mx > viewbox.x + viewbox.width + 6 ||
00530       my > viewbox.y + viewbox.height + 6)
00531     return FALSE;
00532   dragging = true;
00533   drag_relx = mx - viewbox.x; // Save rel. pos.
00534   drag_rely = my - viewbox.y;
00535   return (TRUE);
00536   }
00537 
00538 /*
00539  *  Handle a mouse-release event.
00540  */
00541 
00542 gint Locator::mouse_release
00543   (
00544   GdkEventButton *event
00545   )
00546   {
00547   dragging = false;
00548   return TRUE;
00549   }
00550 
00551 /*
00552  *  Handle a mouse-motion event.
00553  */
00554 
00555 gint Locator::mouse_motion
00556   (
00557   GdkEventMotion *event
00558   )
00559   {
00560   int mx, my;
00561   GdkModifierType state;
00562   if (event->is_hint)
00563     gdk_window_get_pointer(event->window, &mx, &my, &state);
00564   else
00565     {
00566     mx = (int) event->x;
00567     my = (int) event->y;
00568     state = (GdkModifierType) event->state;
00569     }
00570   if (!dragging || !(state & GDK_BUTTON1_MASK))
00571     return FALSE;   // Not dragging with left button.
00572           // Delay sending location to Exult.
00573   goto_mouse(mx + drag_relx, my + drag_rely, true);
00574   return TRUE;
00575   }

Generated on Mon Jul 9 14:42:47 2007 for ExultEngine by  doxygen 1.5.1