00001
00012 #include <gtk/gtk.h>
00013 #include <gdk/gdk.h>
00014 #include <zakdef.h>
00015 #include <simulation.h>
00016 #include <ui.h>
00017 #include <globals.h>
00018 #include <main.h>
00019 #include <drawing.h>
00020 #include <string.h>
00021 #include <strings.h>
00022 #include <assert.h>
00023
00025 static GtkWidget *pw_win;
00026
00028 static GtkWidget *dw_area;
00029
00031 struct tag_pmh {
00032 GdkPixmap *allmap;
00033 GdkPixmap *power;
00034 GdkPixmap *power_mask;
00035 GdkPixmap *water;
00036 GdkPixmap *water_mask;
00037 } pmh;
00038
00040 #define SHOW_POWER 1
00041
00042 #define SHOW_WATER (SHOW_POWER<<1)
00043
00045 static int shown_pixmaps;
00046
00048 GtkWidget *button_power;
00050 GtkWidget *button_water;
00051
00053 static struct button_list {
00054 GtkWidget **button;
00055 int field;
00056 } list_buttons[] = {
00057 { &button_power, SHOW_POWER },
00058 { &button_water, SHOW_WATER },
00059 { NULL, 0 }
00060 };
00061
00067 static void
00068 bpwater_clicked(GtkWidget *widget, gpointer data __attribute__((unused)))
00069 {
00070 int i;
00071 struct button_list *bl;
00072 int newshown_pixmaps = shown_pixmaps;
00073
00074 for (i = 0; list_buttons[i].button != NULL; i++) {
00075 bl = list_buttons + i;
00076 if (*bl->button == widget) {
00077 if (bl->field == shown_pixmaps) {
00078 newshown_pixmaps = 0;
00079 } else {
00080 newshown_pixmaps = bl->field;
00081 }
00082 }
00083 if (bl->field == shown_pixmaps) {
00084 gtk_toggle_button_set_active(
00085 GTK_TOGGLE_BUTTON(*bl->button), FALSE);
00086 }
00087 }
00088 shown_pixmaps = newshown_pixmaps;
00089 gtk_widget_queue_draw(dw_area);
00090 }
00091
00098 static gint
00099 close_window(GtkWidget *wid __attribute__((unused)),
00100 gpointer data __attribute__((unused)))
00101 {
00102 pw_win = NULL;
00103 return (FALSE);
00104 }
00105
00106 void
00107 cleanupMap(void)
00108 {
00109 if (pmh.allmap != NULL) g_object_unref(G_OBJECT(pmh.allmap));
00110 if (pmh.power != NULL) g_object_unref(G_OBJECT(pmh.power));
00111 if (pmh.water != NULL) g_object_unref(G_OBJECT(pmh.water));
00112 if (pmh.power_mask != NULL) g_object_unref(G_OBJECT(pmh.power_mask));
00113 if (pmh.water_mask != NULL) g_object_unref(G_OBJECT(pmh.water_mask));
00114 bzero(&pmh, sizeof (pmh));
00115 }
00116
00118 typedef enum { ccBlank, ccNeed, ccHas } ccr_t;
00119
00121 static GdkColor colBlank = { 0, 0, 0, 0 };
00123 static GdkColor colNeedPower = { 1, 255, 0, 0 };
00125 static GdkColor colNeedWater = { 1, 0, 0, 255 };
00127 static GdkColor colFull = { 2, 255, 255, 255 };
00128
00138 static void
00139 updateAMap(Int16 xpos, Int16 ypos, GdkColor *col, ccr_t carry,
00140 GdkDrawable *dw_ori, GdkDrawable *dw_mask)
00141 {
00142 GdkGC *gc;
00143
00144 if (col == NULL) {
00145 gc = gdk_gc_new(dw_mask);
00146 gdk_gc_set_function(gc, GDK_OR);
00147 if (carry == ccBlank) {
00148 col = &colFull;
00149 } else {
00150 col = &colBlank;
00151 }
00152 gdk_gc_set_foreground(gc, &colFull);
00153 gdk_gc_set_background(gc, &colBlank);
00154 gdk_draw_rectangle(dw_mask, gc, TRUE, xpos * mapTileSize(),
00155 ypos * mapTileSize(), mapTileSize(), mapTileSize());
00156 g_object_unref(gc);
00157 }
00158
00159 gc = gdk_gc_new(dw_ori);
00160 gdk_gc_set_foreground(gc, col);
00161 gdk_draw_rectangle(dw_ori, gc, TRUE, xpos * mapTileSize(),
00162 ypos * mapTileSize(), mapTileSize(), mapTileSize());
00163 g_object_unref(gc);
00164 }
00165
00174 static ccr_t
00175 checkCommon(welem_t world, selem_t flag, carryfn_t carry, UInt8 flagbit)
00176 {
00177 if (!carry(world))
00178 return (ccBlank);
00179 if (flag & flagbit)
00180 return (ccHas);
00181 return (ccNeed);
00182 }
00183
00190 static void
00191 updatePower(Int16 xpos, Int16 ypos, ccr_t has_carry)
00192 {
00193 GdkColor *dc = (has_carry == ccNeed) ? &colNeedPower : NULL;
00194 updateAMap(xpos, ypos, dc, has_carry,
00195 GDK_DRAWABLE(pmh.power), GDK_DRAWABLE(pmh.power_mask));
00196 }
00197
00204 static void
00205 updateWater(Int16 xpos, Int16 ypos, ccr_t has_carry)
00206 {
00207 GdkColor *dc = (has_carry == ccNeed) ? &colNeedWater : NULL;
00208 updateAMap(xpos, ypos, dc, has_carry,
00209 GDK_DRAWABLE(pmh.water), GDK_DRAWABLE(pmh.water_mask));
00210 }
00211
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00242 void
00243 doPixPaint(void)
00244 {
00245 GdkDrawable *dwa = drawable_main_get();
00246
00247 assert(mapTileSize());
00248 assert(getMapWidth());
00249 assert(getMapHeight());
00250 pmh.allmap = gdk_pixmap_new(dwa,
00251 getMapWidth() * mapTileSize(),
00252 getMapHeight() * mapTileSize(), -1);
00253 pmh.power = gdk_pixmap_new(dwa,
00254 getMapWidth() * mapTileSize(),
00255 getMapHeight() * mapTileSize(), -1);
00256 pmh.power_mask = gdk_pixmap_new(dwa,
00257 getMapWidth() * mapTileSize(),
00258 getMapHeight() * mapTileSize(), 1);
00259 pmh.water = gdk_pixmap_new(dwa,
00260 getMapWidth() * mapTileSize(),
00261 getMapHeight() * mapTileSize(), -1);
00262 pmh.water_mask = gdk_pixmap_new(dwa,
00263 getMapWidth() * mapTileSize(),
00264 getMapHeight() * mapTileSize(), 1);
00265
00266 }
00267
00275 static gint
00276 expose_pw(GtkWidget *area,
00277 GdkEventExpose *event,
00278 gpointer data __attribute__((unused)))
00279 {
00280 GdkGC *gc = gdk_gc_new(area->window);
00281 GdkPixmap *pm_ext = NULL;
00282 GdkPixmap *pm_ovl = NULL;
00283
00284 gdk_draw_drawable(
00285 area->window,
00286 gc,
00287 pmh.allmap,
00288 event->area.x,
00289 event->area.y,
00290 event->area.x,
00291 event->area.y,
00292 event->area.width,
00293 event->area.height);
00294
00295 switch (shown_pixmaps) {
00296 case SHOW_POWER:
00297 pm_ext = pmh.power;
00298 pm_ovl = pmh.power_mask;
00299 break;
00300 case SHOW_WATER:
00301 pm_ext = pmh.water;
00302 pm_ovl = pmh.water_mask;
00303 break;
00304 default:
00305 break;
00306 }
00307 if (pm_ext != NULL) {
00308 gdk_gc_set_clip_mask(gc, pm_ovl);
00309 gdk_draw_drawable(
00310 area->window,
00311 gc,
00312 pm_ext,
00313 event->area.x,
00314 event->area.y,
00315 event->area.x,
00316 event->area.y,
00317 event->area.width,
00318 event->area.height);
00319 }
00320
00321 g_object_unref(gc);
00322
00323 return (FALSE);
00324 }
00325
00329 void
00330 showMap(void)
00331 {
00332 GtkWidget *table;
00333
00334 if (pw_win != NULL) {
00335 gtk_widget_show(pw_win);
00336 return;
00337 }
00338
00339 pw_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00340 gtk_window_set_title(GTK_WINDOW(pw_win), "Power/Water Distribution");
00341 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(pw_win), TRUE);
00342
00343 g_signal_connect(G_OBJECT(pw_win), "delete_event",
00344 G_CALLBACK(close_window), NULL);
00345
00346 table = gtk_table_new(2, 2, FALSE);
00347
00348 button_power = gtk_toggle_button_new_with_label("Power Grid");
00349 button_water = gtk_toggle_button_new_with_label("Water Supply");
00350
00351 g_signal_connect(G_OBJECT(button_power), "clicked",
00352 G_CALLBACK(bpwater_clicked), NULL);
00353 g_signal_connect(G_OBJECT(button_water), "clicked",
00354 G_CALLBACK(bpwater_clicked), NULL);
00355
00356 gtk_table_attach(GTK_TABLE(table), button_power, 0, 1, 0, 1, GTK_FILL,
00357 GTK_SHRINK, 2, 2);
00358 gtk_table_attach(GTK_TABLE(table), button_water, 1, 2, 0, 1, GTK_FILL,
00359 GTK_SHRINK, 2, 2);
00360
00361 dw_area = gtk_drawing_area_new();
00362 gtk_widget_set_size_request(dw_area, getMapWidth() * mapTileSize(),
00363 getMapHeight() * mapTileSize());
00364 gtk_table_attach(GTK_TABLE(table), dw_area, 0, 2, 1, 2, GTK_EXPAND,
00365 GTK_EXPAND, 2, 2);
00366 gtk_container_add(GTK_CONTAINER(pw_win), table);
00367
00368 gtk_window_set_policy(GTK_WINDOW(pw_win), FALSE, FALSE, TRUE);
00369
00370 g_signal_connect(G_OBJECT(dw_area), "expose_event",
00371 G_CALLBACK(expose_pw), NULL);
00372
00373 gtk_widget_show_all(table);
00374 gtk_widget_show(pw_win);
00375 }
00376
00377 void
00378 UIPaintMapField(UInt16 xpos, UInt16 ypos, welem_t elem)
00379 {
00380 if (pmh.allmap == NULL)
00381 doPixPaint();
00382
00383 UIDrawMapZone(xpos, ypos, elem,
00384 GDK_DRAWABLE(pmh.allmap));
00385 }
00386
00387 void
00388 UIPaintMapStatus(UInt16 xpos, UInt16 ypos, welem_t world, selem_t status)
00389 {
00390 updatePower(xpos, ypos, checkCommon(world, status, &CarryPower,
00391 POWEREDBIT));
00392 updateWater(xpos, ypos, checkCommon(world, status, &CarryWater,
00393 WATEREDBIT));
00394 }
00395
00399 void
00400 resizeMap(void)
00401 {
00402 cleanupMap();
00403 doPixPaint();
00404 }
00405