2 * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <glib/gi18n.h>
22 #include "editorwidgets.h"
25 * A COMBO BOX with c64 colors.
26 * use color_combo_new for creating and color_combo_get_color for getting color in gdash format.
29 /* this data field always stores the previously selected color. */
30 /* it is needed when a select atari or select rgb dialog is escaped, and we must set the original color. */
31 /* the combo box itself cannot store it, as is is already set to the select atari... or select rgb... line. */
32 #define GDASH_COLOR "gdash-color"
34 static GtkTreePath
*selected_color_path
=NULL
;
45 COLOR_ACTION_SELECT_ATARI
,
46 COLOR_ACTION_SELECT_DTV
,
47 COLOR_ACTION_SELECT_RGB
,
51 * creates a small pixbuf with the specified color
54 color_combo_pixbuf_for_gd_color(GdColor col
)
60 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU
, &x
, &y
);
62 pixbuf
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, FALSE
, 8, x
, y
);
63 pixel
=(gd_color_get_r(col
)<<24) + (gd_color_get_g(col
)<<16) + (gd_color_get_b(col
)<<8);
64 gdk_pixbuf_fill(pixbuf
, pixel
);
69 /* set to a color - first check if that is a c64 color. */
71 gd_color_combo_set(GtkComboBox
*combo
, GdColor color
)
73 g_object_set_data(G_OBJECT(combo
), GDASH_COLOR
, GUINT_TO_POINTER(color
));
75 if (gd_color_is_c64(color
)) {
79 path
=g_strdup_printf("0:%d", gd_color_get_c64_index(color
));
80 gtk_tree_model_get_iter_from_string(gtk_combo_box_get_model(combo
), &iter
, path
);
82 gtk_combo_box_set_active_iter(combo
, &iter
);
85 GtkTreeModel
*model
=gtk_combo_box_get_model(GTK_COMBO_BOX(combo
));
89 gtk_tree_model_get_iter(model
, &iter
, selected_color_path
);
91 pixbuf
=color_combo_pixbuf_for_gd_color(color
);
92 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
, COL_COLOR_CODE
, color
, COL_COLOR_PIXBUF
, pixbuf
, COL_COLOR_NAME
, gd_color_get_visible_name(color
), -1);
93 g_object_unref(pixbuf
); /* now the tree store owns its own reference */
95 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo
), &iter
);
100 color_combo_drawing_area_button_press_event(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
102 GtkDialog
*dialog
=GTK_DIALOG(data
);
104 gtk_dialog_response(dialog
, GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget
), GDASH_COLOR
)));
112 color_combo_changed(GtkWidget
*combo
, gpointer data
)
114 GtkTreeModel
*model
=gtk_combo_box_get_model(GTK_COMBO_BOX(combo
));
118 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo
), &iter
);
119 gtk_tree_model_get(model
, &iter
, COL_COLOR_ACTION
, &action
, -1);
121 case COLOR_ACTION_SELECT_RGB
:
124 GtkColorSelection
*colorsel
;
129 dialog
=gtk_color_selection_dialog_new (_("Select Color"));
130 gtk_window_set_transient_for (GTK_WINDOW (dialog
), GTK_WINDOW (gtk_widget_get_toplevel(combo
)));
132 colorsel
=GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog
)->colorsel
);
134 prevcol
=GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(combo
), GDASH_COLOR
));
135 gc
.red
=gd_color_get_r(prevcol
)<<8;
136 gc
.green
=gd_color_get_g(prevcol
)<<8;
137 gc
.blue
=gd_color_get_b(prevcol
)<<8;
138 gtk_color_selection_set_previous_color (colorsel
, &gc
);
139 gtk_color_selection_set_current_color (colorsel
, &gc
);
140 gtk_color_selection_set_has_palette (colorsel
, TRUE
);
142 gtk_window_present_with_time(GTK_WINDOW(dialog
), gtk_get_current_event_time());
143 response
=gtk_dialog_run(GTK_DIALOG (dialog
));
145 if (response
==GTK_RESPONSE_OK
) {
149 gtk_color_selection_get_current_color(colorsel
, &gc
);
150 color
=gd_color_get_from_rgb(gc
.red
>>8, gc
.green
>>8, gc
.blue
>>8);
151 gd_color_combo_set(GTK_COMBO_BOX(combo
), color
);
153 gd_color_combo_set(GTK_COMBO_BOX(combo
), prevcol
);
156 gtk_widget_destroy (dialog
);
160 case COLOR_ACTION_SELECT_ATARI
:
161 case COLOR_ACTION_SELECT_DTV
:
163 GtkWidget
*dialog
, *table
, *frame
;
167 GdColor (*colorfunc
) (int i
);
171 case COLOR_ACTION_SELECT_ATARI
:
172 title
=_("Select Atari Color");
173 colorfunc
=gd_atari_color
;
175 case COLOR_ACTION_SELECT_DTV
:
176 title
=_("Select C64 DTV Color");
177 colorfunc
=gd_c64dtv_color
;
180 g_assert_not_reached();
183 dialog
=gtk_dialog_new_with_buttons(title
, GTK_WINDOW (gtk_widget_get_toplevel(combo
)), GTK_DIALOG_NO_SEPARATOR
, GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
, NULL
);
184 table
=gtk_table_new(16, 16, TRUE
);
185 for (i
=0; i
<256; i
++) {
190 da
=gtk_drawing_area_new();
192 g_object_set_data(G_OBJECT(da
), GDASH_COLOR
, GUINT_TO_POINTER(i
)); /* attach the color index as data */
193 gtk_widget_add_events(da
, GDK_BUTTON_PRESS_MASK
);
194 gtk_widget_set_tooltip_text(da
, gd_color_get_visible_name(c
));
195 g_signal_connect(G_OBJECT(da
), "button_press_event", G_CALLBACK(color_combo_drawing_area_button_press_event
), dialog
); /* mouse click */
196 color
.red
=gd_color_get_r(c
)*256; /* 256 as gdk expect 16-bit/component */
197 color
.green
=gd_color_get_g(c
)*256;
198 color
.blue
=gd_color_get_b(c
)*256;
199 gtk_widget_modify_bg(da
, GTK_STATE_NORMAL
, &color
);
200 gtk_widget_set_size_request(da
, 16, 16);
201 gtk_table_attach_defaults(GTK_TABLE(table
), da
, i
%16, i
%16+1, i
/16, i
/16+1);
203 frame
=gtk_frame_new(NULL
);
204 gtk_container_set_border_width(GTK_CONTAINER(frame
), 6);
205 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_IN
);
206 gtk_container_add(GTK_CONTAINER(frame
), table
);
207 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog
)->vbox
), frame
);
208 gtk_widget_show_all(GTK_DIALOG(dialog
)->vbox
);
210 prevcol
=GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(combo
), GDASH_COLOR
));
211 result
=gtk_dialog_run(GTK_DIALOG(dialog
));
213 gd_color_combo_set(GTK_COMBO_BOX(combo
), colorfunc(result
));
215 gd_color_combo_set(GTK_COMBO_BOX(combo
), prevcol
);
217 gtk_widget_destroy(dialog
);
221 case COLOR_ACTION_NONE
:
225 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo
), &iter
);
226 gtk_tree_model_get(model
, &iter
, COL_COLOR_CODE
, &c
, -1);
227 g_object_set_data(G_OBJECT(combo
), GDASH_COLOR
, GUINT_TO_POINTER(c
));
232 /* A GtkTreeViewRowSeparatorFunc that demonstrates how rows can be
233 * rendered as separators.
236 color_combo_is_separator (GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer data
)
241 path
=gtk_tree_model_get_path(model
, iter
);
242 result
=!gtk_tree_path_compare(path
, selected_color_path
);
243 gtk_tree_path_free (path
);
249 color_combo_set_sensitive(GtkCellLayout
*cell_layout
, GtkCellRenderer
*cell
, GtkTreeModel
*tree_model
, GtkTreeIter
*iter
, gpointer data
)
251 g_object_set(cell
, "sensitive", !gtk_tree_model_iter_has_child(tree_model
, iter
), NULL
);
254 /* combo box creator. */
256 gd_color_combo_new(const GdColor color
)
258 /* this is the base of the cave editor element combo box.
259 categories are autodetected by their integer values being >O_MAX */
262 GtkCellRenderer
*renderer
;
263 GtkTreeIter iter
, parent
;
266 /* tree store for colors. every combo has its own, as the custom color can be different. */
267 store
=gtk_tree_store_new(4, G_TYPE_INT
, G_TYPE_UINT
, G_TYPE_STRING
, GDK_TYPE_PIXBUF
);
269 /* add 16 c64 colors */
270 gtk_tree_store_append(store
, &parent
, NULL
);
271 gtk_tree_store_set(store
, &parent
, COL_COLOR_CODE
, 0, COL_COLOR_NAME
, _("C64 Colors"), COL_COLOR_PIXBUF
, NULL
, -1);
272 for (i
= 0; i
<16; i
++) {
275 pixbuf
=color_combo_pixbuf_for_gd_color(gd_c64_color(i
));
276 gtk_tree_store_append(store
, &iter
, &parent
);
277 gtk_tree_store_set(store
, &iter
, COL_COLOR_ACTION
, COLOR_ACTION_NONE
, COL_COLOR_CODE
, gd_c64_color(i
), COL_COLOR_NAME
, _(gd_color_get_visible_name(gd_c64_color(i
))), COL_COLOR_PIXBUF
, pixbuf
, -1);
278 g_object_unref (pixbuf
);
280 gtk_tree_store_append(store
, &iter
, NULL
);
281 if (!selected_color_path
)
282 selected_color_path
=gtk_tree_model_get_path(GTK_TREE_MODEL(store
), &iter
);
283 gtk_tree_store_append(store
, &iter
, NULL
);
284 gtk_tree_store_set(store
, &iter
, COL_COLOR_ACTION
, COLOR_ACTION_SELECT_ATARI
, COL_COLOR_CODE
, 0, COL_COLOR_NAME
, _("Atari color..."), COL_COLOR_PIXBUF
, NULL
, -1);
285 gtk_tree_store_append(store
, &iter
, NULL
);
286 gtk_tree_store_set(store
, &iter
, COL_COLOR_ACTION
, COLOR_ACTION_SELECT_DTV
, COL_COLOR_CODE
, 0, COL_COLOR_NAME
, _("C64DTV color..."), COL_COLOR_PIXBUF
, NULL
, -1);
287 gtk_tree_store_append(store
, &iter
, NULL
);
288 gtk_tree_store_set(store
, &iter
, COL_COLOR_ACTION
, COLOR_ACTION_SELECT_RGB
, COL_COLOR_CODE
, 0, COL_COLOR_NAME
, _("RGB color..."), COL_COLOR_PIXBUF
, NULL
, -1);
290 combo
=gtk_combo_box_new_with_model(GTK_TREE_MODEL(store
));
291 /* first column, object image */
292 renderer
=gtk_cell_renderer_pixbuf_new ();
293 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo
), renderer
, FALSE
);
294 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo
), renderer
, "pixbuf", COL_COLOR_PIXBUF
, NULL
);
295 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo
), renderer
, color_combo_set_sensitive
, NULL
, NULL
);
296 /* second column, object name */
297 renderer
= gtk_cell_renderer_text_new ();
298 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo
), renderer
, TRUE
);
299 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo
), renderer
, color_combo_set_sensitive
, NULL
, NULL
);
300 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo
), renderer
, "text", COL_COLOR_NAME
, NULL
);
301 gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(combo
), color_combo_is_separator
, NULL
, NULL
);
303 gd_color_combo_set(GTK_COMBO_BOX(combo
), color
);
304 g_signal_connect(G_OBJECT(combo
), "changed", G_CALLBACK(color_combo_changed
), NULL
);
310 gd_color_combo_get_color(GtkWidget
*widget
)
312 GtkTreeModel
*model
=gtk_combo_box_get_model(GTK_COMBO_BOX(widget
));
316 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget
), &iter
);
317 gtk_tree_model_get(model
, &iter
, COL_COLOR_CODE
, &color
, -1);
335 /****************************************************
337 * create and return a button, which contains
338 * cave elements available in the editor.
339 * an initial value is also selected.
341 #define GDASH_CELL "gdash-cell"
342 #define GDASH_ELEMENT "gdash-element"
343 #define GDASH_HOVER "gdash-hover"
344 #define GDASH_BUTTON "gdash-button"
346 #define GDASH_DIALOG "gdash-dialog"
347 #define GDASH_WINDOW_TITLE "gdash-window-title"
348 #define GDASH_DIALOG_VBOX "gdash-dialog-vbox"
349 #define GDASH_BUTTON_IMAGE "gdash-button-image"
350 #define GDASH_BUTTON_LABEL "gdash-button-label"
352 static int element_button_animcycle
;
354 /* this draws one element in the element selector box. */
356 element_button_drawing_area_expose_event (const GtkWidget
* widget
, const GdkEventExpose
* event
, const gpointer data
)
358 GdkDrawable
*cell
=g_object_get_data(G_OBJECT(widget
), GDASH_CELL
);
364 gdk_draw_drawable (widget
->window
, widget
->style
->black_gc
, cell
, 0, 0, 2, 2, gd_cell_size_editor
, gd_cell_size_editor
);
368 /* this is called when entering and exiting a drawing area with the mouse. */
369 /* so they can be colored when the mouse is over. */
371 element_button_drawing_area_crossing_event (const GtkWidget
*widget
, const GdkEventCrossing
*event
, const gpointer data
)
373 g_object_set_data(G_OBJECT(widget
), GDASH_HOVER
, GINT_TO_POINTER(event
->type
==GDK_ENTER_NOTIFY
));
378 redraw_timeout (gpointer data
)
380 GList
*areas
=(GList
*)data
;
383 element_button_animcycle
=(element_button_animcycle
+1)&7;
385 for (iter
=areas
; iter
!=NULL
; iter
=iter
->next
) {
386 GtkWidget
*da
=(GtkWidget
*)iter
->data
;
391 /* which element is drawn? */
392 element
=(GdElement
)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(da
), GDASH_ELEMENT
));
393 hover
=(gboolean
)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(da
), GDASH_HOVER
));
394 /* get pixbuf index */
395 draw
=gd_elements
[element
].image
;
397 draw
=-draw
+ element_button_animcycle
;
400 /* set cell and queue draw if different from previous */
401 /* at first start, previous is null, so always different. */
402 if (g_object_get_data(G_OBJECT(da
), GDASH_CELL
)!=gd_editor_pixmap(draw
)) {
403 g_object_set_data(G_OBJECT(da
), GDASH_CELL
, gd_editor_pixmap(draw
));
404 gtk_widget_queue_draw(da
);
412 gd_element_button_set(GtkWidget
*button
, const GdElement element
)
414 GtkWidget
*image
, *label
;
415 label
=GTK_WIDGET(g_object_get_data(G_OBJECT(button
), GDASH_BUTTON_LABEL
));
416 image
=GTK_WIDGET(g_object_get_data(G_OBJECT(button
), GDASH_BUTTON_IMAGE
));
418 gtk_image_set_from_pixbuf(GTK_IMAGE(image
), gd_get_element_pixbuf_with_border(element
));
419 gtk_label_set_text(GTK_LABEL(label
), _(gd_elements
[element
].name
));
420 g_object_set_data(G_OBJECT(button
), GDASH_ELEMENT
, GINT_TO_POINTER(element
));
424 element_button_da_clicked(GtkWidget
*da
, GdkEventButton
*event
, gpointer data
)
426 GtkDialog
*dialog
=GTK_DIALOG(data
);
430 /* set the corresponding button to the element selected */
431 element
=(GdElement
)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(da
), GDASH_ELEMENT
));
432 button
=GTK_WIDGET(g_object_get_data(G_OBJECT(da
), GDASH_BUTTON
));
433 gd_element_button_set(button
, element
);
435 /* if this is a modal window, then it is a does-not-stay-open element box. */
436 /* so we issue a dialog response. */
437 if (gtk_window_get_modal(GTK_WINDOW(dialog
)))
438 gtk_dialog_response(dialog
, element
);
440 /* if not modal, it is a stay-open element box. */
441 /* close if left mouse button; stay open for others. */
442 if (event
->button
==1)
443 gtk_widget_destroy(GTK_WIDGET(dialog
));
448 element_button_dialog_destroyed_free_list(GtkWidget
*dialog
, gpointer data
)
450 GList
*areas
=(GList
*) data
;
452 g_source_remove_by_user_data(areas
);
457 element_button_dialog_destroyed_null_pointer(GtkWidget
*dialog
, gpointer data
)
459 g_object_set_data(G_OBJECT(data
), GDASH_DIALOG
, NULL
);
460 g_object_set_data(G_OBJECT(data
), GDASH_DIALOG_VBOX
, NULL
);
464 element_button_dialog_close_button_clicked(GtkWidget
*button
, gpointer data
)
466 /* data is the dialog */
467 gtk_widget_destroy(GTK_WIDGET(data
));
471 element_button_clicked_func(GtkWidget
*button
, gboolean stay_open
)
473 static const GdElement elements
[]= {
475 O_SPACE
, O_DIRT
, O_DIAMOND
, O_STONE
, O_MEGA_STONE
, O_FLYING_DIAMOND
, O_FLYING_STONE
, O_NUT
,
476 O_BRICK
, O_FALLING_WALL
, O_BRICK_EATABLE
, O_BRICK_NON_SLOPED
, O_SPACE
, O_STEEL
, O_STEEL_EATABLE
, O_STEEL_EXPLODABLE
,
478 O_INBOX
, O_PRE_OUTBOX
, O_PRE_INVIS_OUTBOX
, O_PLAYER_GLUED
, O_VOODOO
, O_SPACE
, O_SPACE
, O_SKELETON
,
479 O_WALLED_KEY_1
, O_WALLED_KEY_2
, O_WALLED_KEY_3
, O_WALLED_DIAMOND
, O_STEEL_SLOPED_UP_RIGHT
, O_STEEL_SLOPED_UP_LEFT
, O_STEEL_SLOPED_DOWN_LEFT
, O_STEEL_SLOPED_DOWN_RIGHT
,
481 O_AMOEBA
, O_AMOEBA_2
, O_SLIME
, O_ACID
, O_MAGIC_WALL
, O_WATER
, O_LAVA
, O_REPLICATOR
,
482 O_KEY_1
, O_KEY_2
, O_KEY_3
, O_DIAMOND_KEY
, O_BRICK_SLOPED_DOWN_RIGHT
, O_BRICK_SLOPED_DOWN_LEFT
, O_BRICK_SLOPED_UP_LEFT
, O_BRICK_SLOPED_UP_RIGHT
,
484 O_BOMB
, O_CLOCK
, O_POT
, O_BOX
, O_SWEET
, O_PNEUMATIC_HAMMER
, O_NITRO_PACK
, O_TELEPORTER
,
485 O_DOOR_1
, O_DOOR_2
, O_DOOR_3
, O_TRAPPED_DIAMOND
, O_DIRT_SLOPED_UP_RIGHT
, O_DIRT_SLOPED_UP_LEFT
, O_DIRT_SLOPED_DOWN_LEFT
, O_DIRT_SLOPED_DOWN_RIGHT
,
487 O_GRAVITY_SWITCH
, O_CREATURE_SWITCH
, O_BITER_SWITCH
, O_EXPANDING_WALL_SWITCH
, O_REPLICATOR_SWITCH
, O_SPACE
, O_CONVEYOR_SWITCH
, O_CONVEYOR_DIR_SWITCH
,
488 O_H_EXPANDING_WALL
, O_V_EXPANDING_WALL
, O_EXPANDING_WALL
, O_SPACE
, O_DIRT_BALL
, O_DIRT_LOOSE
, O_SPACE
, O_NONE
,
490 O_CONVEYOR_LEFT
, O_CONVEYOR_RIGHT
, O_SPACE
, O_SPACE
, O_SPACE
, O_DIRT_GLUED
, O_DIAMOND_GLUED
, O_STONE_GLUED
,
491 O_H_EXPANDING_STEEL_WALL
, O_V_EXPANDING_STEEL_WALL
, O_EXPANDING_STEEL_WALL
, O_BLADDER_SPENDER
, O_BLADDER
, O_GHOST
, O_WAITING_STONE
, O_CHASING_STONE
,
493 O_SPACE
, O_FIREFLY_2
, O_ALT_FIREFLY_2
, O_SPACE
, O_SPACE
, O_BUTTER_2
, O_ALT_BUTTER_2
, O_SPACE
, O_SPACE
, O_STONEFLY_2
, O_SPACE
, O_COW_2
, O_BITER_1
, O_SPACE
, O_SPACE
, O_DRAGONFLY_2
,
494 O_FIREFLY_1
, O_FIREFLY_3
, O_ALT_FIREFLY_1
, O_ALT_FIREFLY_3
, O_BUTTER_1
, O_BUTTER_3
, O_ALT_BUTTER_1
, O_ALT_BUTTER_3
, O_STONEFLY_1
, O_STONEFLY_3
, O_COW_1
, O_COW_3
, O_BITER_4
, O_BITER_2
, O_DRAGONFLY_1
, O_DRAGONFLY_3
,
495 O_SPACE
, O_FIREFLY_4
, O_ALT_FIREFLY_4
, O_SPACE
, O_SPACE
, O_BUTTER_4
, O_ALT_BUTTER_4
, O_SPACE
, O_SPACE
, O_STONEFLY_4
, O_SPACE
, O_COW_4
, O_BITER_3
, O_SPACE
, O_SPACE
, O_DRAGONFLY_4
,
498 O_DIAMOND_F
, O_STONE_F
, O_MEGA_STONE_F
, O_FLYING_DIAMOND_F
, O_FLYING_STONE_F
, O_FALLING_WALL_F
, O_NITRO_PACK_F
, O_NUT_F
, O_PRE_PL_1
, O_PRE_PL_2
, O_PRE_PL_3
, O_PLAYER
, O_PLAYER_BOMB
, O_PLAYER_STIRRING
, O_OUTBOX
, O_INVIS_OUTBOX
,
500 O_BLADDER_1
, O_BLADDER_2
, O_BLADDER_3
, O_BLADDER_4
, O_BLADDER_5
, O_BLADDER_6
, O_BLADDER_7
, O_BLADDER_8
, O_DIRT2
,
501 O_COW_ENCLOSED_1
, O_COW_ENCLOSED_2
, O_COW_ENCLOSED_3
, O_COW_ENCLOSED_4
, O_COW_ENCLOSED_5
, O_COW_ENCLOSED_6
, O_COW_ENCLOSED_7
,
503 O_WATER_1
, O_WATER_2
, O_WATER_3
, O_WATER_4
, O_WATER_5
, O_WATER_6
, O_WATER_7
, O_WATER_8
,
504 O_WATER_9
, O_WATER_10
, O_WATER_11
, O_WATER_12
, O_WATER_13
, O_WATER_14
, O_WATER_15
, O_WATER_16
,
506 O_BOMB_TICK_1
, O_BOMB_TICK_2
, O_BOMB_TICK_3
, O_BOMB_TICK_4
, O_BOMB_TICK_5
, O_BOMB_TICK_6
, O_BOMB_TICK_7
,
507 O_BOMB_EXPL_1
, O_BOMB_EXPL_2
, O_BOMB_EXPL_3
, O_BOMB_EXPL_4
, O_NUT_EXPL_1
, O_NUT_EXPL_2
, O_NUT_EXPL_3
, O_NUT_EXPL_4
, O_UNKNOWN
,
509 O_EXPLODE_1
, O_EXPLODE_2
, O_EXPLODE_3
, O_EXPLODE_4
, O_EXPLODE_5
, O_TIME_PENALTY
,
510 O_PRE_DIA_1
, O_PRE_DIA_2
, O_PRE_DIA_3
, O_PRE_DIA_4
, O_PRE_DIA_5
, O_NITRO_PACK_EXPLODE
, O_NITRO_EXPL_1
, O_NITRO_EXPL_2
, O_NITRO_EXPL_3
, O_NITRO_EXPL_4
,
511 O_PRE_STONE_1
, O_PRE_STONE_2
, O_PRE_STONE_3
, O_PRE_STONE_4
, O_PRE_STEEL_1
, O_PRE_STEEL_2
, O_PRE_STEEL_3
, O_PRE_STEEL_4
,
512 O_PRE_CLOCK_1
, O_PRE_CLOCK_2
, O_PRE_CLOCK_3
, O_PRE_CLOCK_4
, O_GHOST_EXPL_1
, O_GHOST_EXPL_2
, O_GHOST_EXPL_3
, O_GHOST_EXPL_4
,
520 GtkWidget
*dialog
, *expander
, *table
, *table2
, *align
, *vbox
;
524 /* if the dialog is already open, only show it. */
525 dialog
=(GtkWidget
*)(g_object_get_data(G_OBJECT(button
), GDASH_DIALOG
));
527 gtk_window_present(GTK_WINDOW(dialog
));
532 /* elements dialog with no buttons; clicking on an element will do the trick. */
533 dialog
=gtk_dialog_new();
534 gtk_window_set_transient_for(GTK_WINDOW(dialog
), GTK_WINDOW(gtk_widget_get_toplevel(button
)));
535 gtk_window_set_title(GTK_WINDOW(dialog
), g_object_get_data(G_OBJECT(button
), GDASH_WINDOW_TITLE
));
536 gtk_dialog_set_has_separator(GTK_DIALOG(dialog
), FALSE
);
537 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
538 gtk_window_set_resizable(GTK_WINDOW(dialog
), FALSE
);
539 /* associate the dialog with the button, so we know that it is open */
540 g_object_set_data(G_OBJECT(button
), GDASH_DIALOG
, dialog
);
542 vbox
=gtk_vbox_new(FALSE
, 0);
543 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog
)->vbox
), vbox
);
544 g_object_set_data(G_OBJECT(button
), GDASH_DIALOG_VBOX
, vbox
);
546 align
=gtk_alignment_new(0, 0.5, 0, 0);
547 gtk_container_add(GTK_CONTAINER(align
), gtk_label_new(_("Normal elements")));
548 gtk_box_pack_start_defaults(GTK_BOX(vbox
), align
);
551 table
=gtk_table_new(0, 0, TRUE
);
552 gtk_container_set_border_width(GTK_CONTAINER(table
), 6);
553 gtk_box_pack_start_defaults(GTK_BOX(vbox
), table
);
555 expander
=gtk_expander_new(_("For effects"));
556 table2
=gtk_table_new(0, 0, TRUE
);
557 gtk_container_set_border_width(GTK_CONTAINER(table2
), 6);
558 gtk_container_add(GTK_CONTAINER(expander
), table2
);
559 gtk_box_pack_start_defaults(GTK_BOX(vbox
), expander
);
561 /* color for background around elements. */
562 /* gdkcolors are 16bit, we should *256, but instead *200 so a bit darker. */
563 c
.red
=gd_color_get_r(gd_current_background_color())*200;
564 c
.green
=gd_color_get_g(gd_current_background_color())*200;
565 c
.blue
=gd_color_get_b(gd_current_background_color())*200;
566 /* create drawing areas */
567 for (i
=0; i
<G_N_ELEMENTS(elements
); i
++) {
570 da
=gtk_drawing_area_new();
571 gtk_widget_modify_bg(da
, GTK_STATE_NORMAL
, &c
);
572 areas
=g_list_prepend(areas
, da
); /* put in list for animation timeout, that one will request redraw on them */
573 gtk_widget_add_events(da
, GDK_BUTTON_PRESS_MASK
|GDK_LEAVE_NOTIFY_MASK
|GDK_ENTER_NOTIFY_MASK
);
574 g_object_set_data(G_OBJECT(da
), GDASH_ELEMENT
, GINT_TO_POINTER(elements
[i
]));
575 g_object_set_data(G_OBJECT(da
), GDASH_BUTTON
, button
); /* button to update on click */
576 gtk_widget_set_size_request(da
, gd_cell_size_editor
+4, gd_cell_size_editor
+4); /* 2px border around them */
577 gtk_widget_set_tooltip_text(da
, _(gd_elements
[elements
[i
]].name
));
578 g_signal_connect(G_OBJECT(da
), "expose-event", G_CALLBACK(element_button_drawing_area_expose_event
), GINT_TO_POINTER(elements
[i
]));
579 g_signal_connect(G_OBJECT(da
), "leave-notify-event", G_CALLBACK(element_button_drawing_area_crossing_event
), NULL
);
580 g_signal_connect(G_OBJECT(da
), "enter-notify-event", G_CALLBACK(element_button_drawing_area_crossing_event
), NULL
);
581 g_signal_connect(G_OBJECT(da
), "button-press-event", G_CALLBACK(element_button_da_clicked
), dialog
);
582 if (elements
[i
]==O_DIAMOND_F
)
583 /* the dirt2 the first element to be put in the effect list; from that one, always use table2 */
586 gtk_table_attach_defaults(GTK_TABLE(table
), GTK_WIDGET(da
), i
%cols
, i
%cols
+1, i
/cols
, i
/cols
+1);
590 gtk_table_attach_defaults(GTK_TABLE(table2
), GTK_WIDGET(da
), j
%cols
, j
%cols
+1, j
/cols
, j
/cols
+1);
595 /* add a timeout which animates the drawing areas */
596 g_timeout_add(40, redraw_timeout
, areas
);
597 /* if the dialog is destroyed, we must free the list which contains the drawing areas */
598 g_signal_connect(G_OBJECT(dialog
), "destroy", G_CALLBACK(element_button_dialog_destroyed_free_list
), areas
);
599 /* also remember that the button no longer has its own dialog open */
600 g_signal_connect(G_OBJECT(dialog
), "destroy", G_CALLBACK(element_button_dialog_destroyed_null_pointer
), button
);
604 gtk_widget_show_all(dialog
);
605 gtk_dialog_run(GTK_DIALOG(dialog
));
606 gtk_widget_destroy(dialog
);
608 /* if it is a stay-open element box, add a button which (also) closes it */
609 GtkWidget
*close_button
;
611 close_button
=gtk_button_new_from_stock(GTK_STOCK_CLOSE
);
612 gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog
)->action_area
), close_button
, FALSE
, FALSE
, 0);
613 g_signal_connect(G_OBJECT(close_button
), "clicked", (GCallback
) element_button_dialog_close_button_clicked
, dialog
);
615 gtk_widget_show_all(dialog
);
616 gtk_window_present_with_time(GTK_WINDOW(dialog
), gtk_get_current_event_time());
621 gd_element_button_get (GtkWidget
*button
)
623 gpointer element
=g_object_get_data (G_OBJECT(button
), GDASH_ELEMENT
);
624 return (GdElement
)GPOINTER_TO_INT(element
);
627 /* the pixbufs might be changed during the lifetime of an element button. *
628 * for example, when colors of a cave are redefined. so this is made
629 * global and can be called. */
631 gd_element_button_update_pixbuf(GtkWidget
*button
)
633 /* set the same as it already shows, but pixbuf update will be triggered by this */
634 gd_element_button_set(button
, gd_element_button_get(button
));
638 element_button_clicked_stay_open(GtkWidget
*button
, gpointer data
)
640 element_button_clicked_func(button
, TRUE
);
644 element_button_clicked_modal(GtkWidget
*button
, gpointer data
)
646 element_button_clicked_func(button
, FALSE
);
649 /* set the title of the window associated with this element button. */
650 /* if the window is already open, also set the title there. */
652 gd_element_button_set_dialog_title(GtkWidget
*button
, const char *title
)
657 /* get original title, and free if needed */
658 old_title
=g_object_get_data(G_OBJECT(button
), GDASH_WINDOW_TITLE
);
660 /* remember new title */
661 g_object_set_data(G_OBJECT(button
), GDASH_WINDOW_TITLE
, title
?g_strdup(title
):g_strdup(_("Elements")));
663 /* if it has its own window open at the moment, also set it */
664 dialog
=g_object_get_data(G_OBJECT(button
), GDASH_DIALOG
);
666 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
671 gd_element_button_set_dialog_sensitive(GtkWidget
*button
, gboolean sens
)
675 vbox
=g_object_get_data(G_OBJECT(button
), GDASH_DIALOG_VBOX
);
677 gtk_widget_set_sensitive(vbox
, sens
);
680 /* frees the special title text, and optionally destroys the dialog, if exists. */
682 element_button_destroyed(GtkWidget
*button
, gpointer data
)
687 title
=g_object_get_data(G_OBJECT(button
), GDASH_WINDOW_TITLE
);
689 /* if it has a dialog open for any reason, close that also */
690 dialog
=g_object_get_data(G_OBJECT(button
), GDASH_DIALOG
);
692 gtk_widget_destroy(dialog
);
695 /* creates a new element button. optionally the dialog created by
696 * the particular button can stay open, and accept many clicks.
697 * also, it can have some title line, like "draw element" */
699 gd_element_button_new(GdElement initial_element
, gboolean stays_open
, const char *special_title
)
701 GtkWidget
*button
, *image
, *label
, *hbox
;
703 button
=gtk_button_new();
704 hbox
=gtk_hbox_new(FALSE
, 3);
705 gtk_container_add(GTK_CONTAINER(button
), hbox
);
706 label
=gtk_label_new(NULL
);
707 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5); /* left-align label */
708 gtk_label_set_ellipsize(GTK_LABEL(label
), PANGO_ELLIPSIZE_MIDDLE
);
709 image
=gtk_image_new();
710 gtk_box_pack_start(GTK_BOX(hbox
), image
, FALSE
, FALSE
, 0);
711 gtk_box_pack_start(GTK_BOX(hbox
), label
, TRUE
, TRUE
, 0);
712 g_object_set_data(G_OBJECT(button
), GDASH_BUTTON_IMAGE
, image
);
713 g_object_set_data(G_OBJECT(button
), GDASH_BUTTON_LABEL
, label
);
715 gtk_widget_set_size_request(button
, 96, -1); /* minimum width 96px */
716 g_signal_connect(G_OBJECT(button
), "destroy", (GCallback
) element_button_destroyed
, NULL
);
718 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(element_button_clicked_stay_open
), NULL
);
720 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(element_button_clicked_modal
), NULL
);
722 /* set the associated string which will be the title of the element box window opened */
723 gd_element_button_set_dialog_title(button
, special_title
);
725 gd_element_button_set(button
, initial_element
);
729 #undef GDASH_BUTTON_IMAGE
730 #undef GDASH_BUTTON_LABEL
731 #undef GDASH_WINDOW_TITLE
732 #undef GDASH_DIALOG_VBOX
762 /* directions to be shown, and corresponding icons. */
763 static const GdDirection direction_combo_shown_directions
[]= { MV_UP
, MV_RIGHT
, MV_DOWN
, MV_LEFT
};
764 static const char *direction_combo_shown_icons
[]= { GTK_STOCK_GO_UP
, GTK_STOCK_GO_FORWARD
, GTK_STOCK_GO_DOWN
, GTK_STOCK_GO_BACK
};
767 gd_direction_combo_new(const GdDirection initial
)
770 static GtkListStore
*store
=NULL
;
771 GtkCellRenderer
*renderer
;
774 /* create list, if did not do so far. */
780 cellview
=gtk_cell_view_new();
781 store
=gtk_list_store_new (NUM_DIR_COLS
, GDK_TYPE_PIXBUF
, G_TYPE_STRING
);
783 for (i
=0; i
<G_N_ELEMENTS(direction_combo_shown_directions
); i
++) {
784 gtk_list_store_append(store
, &iter
);
785 pixbuf
=gtk_widget_render_icon(cellview
, direction_combo_shown_icons
[i
], GTK_ICON_SIZE_MENU
, NULL
);
786 gtk_list_store_set(store
, &iter
, DIR_PIXBUF_COL
, pixbuf
, DIR_TEXT_COL
, _(gd_direction_get_visible_name(direction_combo_shown_directions
[i
])), -1);
789 gtk_widget_destroy(cellview
);
792 /* create combo box and renderer for icon and text */
793 combo
=gtk_combo_box_new_with_model(GTK_TREE_MODEL(store
));
794 renderer
=gtk_cell_renderer_pixbuf_new ();
795 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo
), renderer
, FALSE
);
796 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo
), renderer
, "pixbuf", DIR_PIXBUF_COL
, NULL
);
797 renderer
=gtk_cell_renderer_text_new ();
798 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo
), renderer
, FALSE
);
799 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo
), renderer
, "text", DIR_TEXT_COL
, NULL
);
801 /* set to initial value */
802 for (i
=0; i
<G_N_ELEMENTS(direction_combo_shown_directions
); i
++)
803 if (direction_combo_shown_directions
[i
]==initial
)
804 gtk_combo_box_set_active(GTK_COMBO_BOX(combo
), i
);
810 gd_direction_combo_get_direction(GtkWidget
*combo
)
812 return (GdDirection
) direction_combo_shown_directions
[gtk_combo_box_get_active(GTK_COMBO_BOX(combo
))];
816 /*****************************************************/
829 gd_scheduling_combo_new(const GdScheduling initial
)
834 combo
=gtk_combo_box_new_text();
836 for (i
=0; i
<GD_SCHEDULING_MAX
; i
++)
837 gtk_combo_box_append_text(GTK_COMBO_BOX(combo
), _(gd_scheduling_get_visible_name((GdScheduling
) i
)));
839 gtk_combo_box_set_active(GTK_COMBO_BOX(combo
), initial
);
845 gd_scheduling_combo_get_scheduling(GtkWidget
*combo
)
847 return (GdScheduling
)(gtk_combo_box_get_active(GTK_COMBO_BOX(combo
)));