1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 #include <stdio.h>
19 #include <stdlib.h>
20
21 #include <X11/Intrinsic.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xaw/Form.h>
24 #include <X11/Xaw/Label.h>
25 #include <X11/Xaw/SimpleMenu.h>
26 #include <X11/Xaw/Command.h>
27 #include <X11/Xaw/List.h>
28 #include <X11/Xaw/Viewport.h>
29
30 #include "fcintl.h"
31 #include "game.h"
32 #include "map.h"
33 #include "mem.h"
34 #include "packets.h"
35 #include "player.h"
36
37 #include "chatline.h"
38 #include "citydlg.h"
39 #include "gui_main.h"
40 #include "gui_stuff.h"
41 #include "mapview.h"
42 #include "options.h"
43
44 #include "messagewin.h"
45
46 static Widget meswin_dialog_shell;
47 static Widget meswin_form;
48 static Widget meswin_label;
49 static Widget meswin_list;
50 static Widget meswin_viewport;
51 static Widget meswin_close_command;
52 static Widget meswin_goto_command;
53 static Widget meswin_popcity_command;
54 static bool meswin_dialog_shell_is_raised;
55
56 static void create_meswin_dialog(bool raise);
57 static void meswin_scroll_down(void);
58 static void meswin_close_callback(Widget w, XtPointer client_data,
59 XtPointer call_data);
60 static void meswin_list_callback(Widget w, XtPointer client_data,
61 XtPointer call_data);
62 static void meswin_goto_callback(Widget w, XtPointer client_data,
63 XtPointer call_data);
64 static void meswin_popcity_callback(Widget w, XtPointer client_data,
65 XtPointer call_data);
66
67 static CONST_FOR_XAW_LIST_CHANGE char *dummy_message_list[] = {
68 " ", 0 };
69
70 #define N_MSG_VIEW 24 /* max before scrolling happens */
71
72 /****************************************************************
73 popup the dialog 10% inside the main-window
74 *****************************************************************/
meswin_dialog_popup(bool raise)75 void meswin_dialog_popup(bool raise)
76 {
77 int updated = 0;
78
79 meswin_dialog_shell_is_raised = raise;
80
81 if(!meswin_dialog_shell) {
82 create_meswin_dialog(raise);
83 updated = 1; /* create_ calls update_ */
84 }
85
86 if (raise) {
87 XtSetSensitive(main_form, FALSE);
88 }
89
90 xaw_set_relative_position(toplevel, meswin_dialog_shell, 25, 25);
91 XtPopup(meswin_dialog_shell, XtGrabNone);
92 if (!updated) {
93 real_meswin_dialog_update(NULL);
94 }
95
96 /* Is this necessary here?
97 * from popup_city_report_dialog():
98 * force refresh of viewport so the scrollbar is added.
99 * Buggy sun athena requires this
100 */
101 XtVaSetValues(meswin_viewport, XtNforceBars, True, NULL);
102
103 meswin_scroll_down();
104 }
105
106 /****************************************************************
107 Closes the message window dialog.
108 *****************************************************************/
meswin_dialog_popdown(void)109 void meswin_dialog_popdown(void)
110 {
111 if (meswin_dialog_shell) {
112 if (meswin_dialog_shell_is_raised) {
113 XtSetSensitive(main_form, TRUE);
114 }
115 XtDestroyWidget(meswin_dialog_shell);
116 meswin_dialog_shell = 0;
117 }
118 }
119
120 /****************************************************************
121 ...
122 *****************************************************************/
meswin_dialog_is_open(void)123 bool meswin_dialog_is_open(void)
124 {
125 return meswin_dialog_shell != NULL;
126 }
127
128 /* This is set when we are creating the message window and it is not popped
129 * up yet. We can't scroll, since Xaw may crash - see PR#2794. */
130 static bool creating = FALSE;
131
132 /****************************************************************
133 ...
134 *****************************************************************/
create_meswin_dialog(bool raise)135 static void create_meswin_dialog(bool raise)
136 {
137 creating = TRUE;
138
139 meswin_dialog_shell =
140 I_IN(I_T(XtCreatePopupShell("meswinpopup",
141 raise ? transientShellWidgetClass
142 : topLevelShellWidgetClass,
143 toplevel, NULL, 0)));
144
145 meswin_form = XtVaCreateManagedWidget("meswinform",
146 formWidgetClass,
147 meswin_dialog_shell, NULL);
148
149 meswin_label =
150 I_L(XtVaCreateManagedWidget("meswinlabel", labelWidgetClass,
151 meswin_form, NULL));
152
153 meswin_viewport = XtVaCreateManagedWidget("meswinviewport",
154 viewportWidgetClass,
155 meswin_form,
156 NULL);
157
158 meswin_list = XtVaCreateManagedWidget("meswinlist",
159 listWidgetClass,
160 meswin_viewport,
161 XtNlist,
162 (XtArgVal)dummy_message_list,
163 NULL);
164
165 meswin_close_command =
166 I_L(XtVaCreateManagedWidget("meswinclosecommand", commandWidgetClass,
167 meswin_form, NULL));
168
169 meswin_goto_command =
170 I_L(XtVaCreateManagedWidget("meswingotocommand", commandWidgetClass,
171 meswin_form,
172 XtNsensitive, False,
173 NULL));
174
175 meswin_popcity_command =
176 I_L(XtVaCreateManagedWidget("meswinpopcitycommand", commandWidgetClass,
177 meswin_form,
178 XtNsensitive, False,
179 NULL));
180
181 XtAddCallback(meswin_list, XtNcallback, meswin_list_callback,
182 NULL);
183
184 XtAddCallback(meswin_close_command, XtNcallback, meswin_close_callback,
185 NULL);
186
187 XtAddCallback(meswin_goto_command, XtNcallback, meswin_goto_callback,
188 NULL);
189
190 XtAddCallback(meswin_popcity_command, XtNcallback, meswin_popcity_callback,
191 NULL);
192
193 real_meswin_dialog_update(NULL);
194
195 XtRealizeWidget(meswin_dialog_shell);
196
197 XSetWMProtocols(display, XtWindow(meswin_dialog_shell),
198 &wm_delete_window, 1);
199 XtOverrideTranslations(meswin_dialog_shell,
200 XtParseTranslationTable("<Message>WM_PROTOCOLS: msg-close-messages()"));
201
202 creating = FALSE;
203 }
204
205 /**************************************************************************
206 This scrolls the messages window down to the bottom.
207 NOTE: it seems this must not be called until _after_ meswin_dialog_shell
208 is ...? realized, popped up, ... something.
209 Its a toss-up whether we _should_ scroll the window down:
210 Against: user will likely want to read from the top and scroll down manually.
211 For: if we don't scroll down, new messages which appear at the bottom
212 (including combat results etc) will be easily missed.
213 **************************************************************************/
meswin_scroll_down(void)214 static void meswin_scroll_down(void)
215 {
216 Dimension height;
217 int pos;
218
219 if (!meswin_dialog_shell || creating) {
220 return;
221 }
222 if (meswin_get_num_messages() <= N_MSG_VIEW) {
223 return;
224 }
225
226 XtVaGetValues(meswin_list, XtNheight, &height, NULL);
227 pos = (((double) (meswin_get_num_messages() - 1))
228 / meswin_get_num_messages()) * height;
229 XawViewportSetCoordinates(meswin_viewport, 0, pos);
230 }
231
232 /**************************************************************************
233 ...
234 **************************************************************************/
real_meswin_dialog_update(void * unused)235 void real_meswin_dialog_update(void *unused)
236 {
237 Dimension height, iheight, width, oldheight, newheight;
238 int i, num = meswin_get_num_messages();
239
240 XawFormDoLayout(meswin_form, False);
241
242 XtVaGetValues(meswin_viewport, XtNheight, &oldheight, NULL);
243
244 if (num == 0) {
245 XawListChange(meswin_list, dummy_message_list, 1, 0, True);
246 } else {
247 /* strings will not be freed */
248 static CONST_FOR_XAW_LIST_CHANGE char **strings = NULL;
249
250 strings = fc_realloc(strings, num * sizeof(char *));
251
252 for (i = 0; i < num; i++) {
253 strings[i] = meswin_get_message(i)->descr;
254 }
255
256 XawListChange(meswin_list, strings, num, 0, True);
257 }
258
259 /* Much of the following copied from city_report_dialog_update() */
260 XtVaGetValues(meswin_list, XtNlongest, &i, NULL);
261 width = i + 10;
262 /* I don't know the proper way to set the width of this viewport widget.
263 Someone who knows is more than welcome to fix this */
264 XtVaSetValues(meswin_viewport, XtNwidth, width + 15, NULL);
265 XtVaSetValues(meswin_label, XtNwidth, width + 15, NULL);
266
267 /* Seems have to do this here so we get the correct height below. */
268 XawFormDoLayout(meswin_form, True);
269
270 if (num <= N_MSG_VIEW) {
271 XtVaGetValues(meswin_list, XtNheight, &height, NULL);
272 if ((oldheight == 0) || (num == 0)) {
273 XtVaSetValues(meswin_viewport, XtNheight, height, NULL);
274 } else {
275 XtVaGetValues(meswin_form, XtNheight, &newheight, NULL);
276 newheight = newheight + height - oldheight;
277 XtVaSetValues(meswin_form, XtNheight, newheight, NULL);
278 }
279 } else {
280 XtVaGetValues(meswin_list, XtNheight, &height, NULL);
281 XtVaGetValues(meswin_list, XtNinternalHeight, &iheight, NULL);
282 height -= (iheight * 2);
283 height /= num;
284 height *= N_MSG_VIEW;
285 height += (iheight * 2);
286 if (height != oldheight) {
287 if (oldheight == 0) {
288 XtVaSetValues(meswin_viewport, XtNheight, height, NULL);
289 } else {
290 XtVaGetValues(meswin_form, XtNheight, &newheight, NULL);
291 newheight = newheight + height - oldheight;
292 XtVaSetValues(meswin_form, XtNheight, newheight, NULL);
293 }
294 }
295 meswin_scroll_down();
296 }
297
298 XtSetSensitive(meswin_goto_command, FALSE);
299 XtSetSensitive(meswin_popcity_command, FALSE);
300 }
301
302 /**************************************************************************
303 ...
304 **************************************************************************/
meswin_list_callback(Widget w,XtPointer client_data,XtPointer call_data)305 static void meswin_list_callback(Widget w, XtPointer client_data,
306 XtPointer call_data)
307 {
308 XawListReturnStruct *ret = XawListShowCurrent(meswin_list);
309
310 if ((ret->list_index != XAW_LIST_NONE)
311 && (meswin_get_num_messages() != 0)) {
312 const struct message *message = meswin_get_message(ret->list_index);
313
314 XtSetSensitive(meswin_goto_command, message->location_ok ? True : False);
315 XtSetSensitive(meswin_popcity_command, message->city_ok ? True : False);
316 } else {
317 XtSetSensitive(meswin_goto_command, False);
318 XtSetSensitive(meswin_popcity_command, False);
319 }
320 }
321
322 /**************************************************************************
323 ...
324 **************************************************************************/
meswin_close_callback(Widget w,XtPointer client_data,XtPointer call_data)325 static void meswin_close_callback(Widget w, XtPointer client_data,
326 XtPointer call_data)
327 {
328 meswin_dialog_popdown();
329 }
330
331 /****************************************************************
332 ...
333 *****************************************************************/
meswin_msg_close(Widget w)334 void meswin_msg_close(Widget w)
335 {
336 meswin_close_callback(w, NULL, NULL);
337 }
338
339 /**************************************************************************
340 ...
341 **************************************************************************/
meswin_goto_callback(Widget w,XtPointer client_data,XtPointer call_data)342 static void meswin_goto_callback(Widget w, XtPointer client_data,
343 XtPointer call_data)
344 {
345 XawListReturnStruct *ret = XawListShowCurrent(meswin_list);
346
347 if (ret->list_index != XAW_LIST_NONE) {
348 meswin_goto(ret->list_index);
349 }
350 }
351
352 /**************************************************************************
353 ...
354 **************************************************************************/
meswin_popcity_callback(Widget w,XtPointer client_data,XtPointer call_data)355 static void meswin_popcity_callback(Widget w, XtPointer client_data,
356 XtPointer call_data)
357 {
358 XawListReturnStruct *ret = XawListShowCurrent(meswin_list);
359
360 if (ret->list_index != XAW_LIST_NONE) {
361 meswin_popup_city(ret->list_index);
362 }
363 }
364