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)
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 ***********************************************************************/
15 #include <fc_config.h>
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>
40 #include "gui_stuff.h"
44 #include "messagewin.h"
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
;
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
,
60 static void meswin_list_callback(Widget w
, XtPointer client_data
,
62 static void meswin_goto_callback(Widget w
, XtPointer client_data
,
64 static void meswin_popcity_callback(Widget w
, XtPointer client_data
,
67 static char *dummy_message_list
[] = {
70 #define N_MSG_VIEW 24 /* max before scrolling happens */
72 /****************************************************************
73 popup the dialog 10% inside the main-window
74 *****************************************************************/
75 void meswin_dialog_popup(bool raise
)
79 meswin_dialog_shell_is_raised
= raise
;
81 if(!meswin_dialog_shell
) {
82 create_meswin_dialog(raise
);
83 updated
= 1; /* create_ calls update_ */
87 XtSetSensitive(main_form
, FALSE
);
90 xaw_set_relative_position(toplevel
, meswin_dialog_shell
, 25, 25);
91 XtPopup(meswin_dialog_shell
, XtGrabNone
);
93 real_meswin_dialog_update();
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
101 XtVaSetValues(meswin_viewport
, XtNforceBars
, True
, NULL
);
103 meswin_scroll_down();
106 /****************************************************************
107 Closes the message window dialog.
108 *****************************************************************/
109 void meswin_dialog_popdown(void)
111 if (meswin_dialog_shell
) {
112 if (meswin_dialog_shell_is_raised
) {
113 XtSetSensitive(main_form
, TRUE
);
115 XtDestroyWidget(meswin_dialog_shell
);
116 meswin_dialog_shell
= 0;
120 /****************************************************************
122 *****************************************************************/
123 bool meswin_dialog_is_open(void)
125 return meswin_dialog_shell
!= NULL
;
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
;
132 /****************************************************************
134 *****************************************************************/
135 static void create_meswin_dialog(bool raise
)
139 meswin_dialog_shell
=
140 I_IN(I_T(XtCreatePopupShell("meswinpopup",
141 raise
? transientShellWidgetClass
142 : topLevelShellWidgetClass
,
143 toplevel
, NULL
, 0)));
145 meswin_form
= XtVaCreateManagedWidget("meswinform",
147 meswin_dialog_shell
, NULL
);
150 I_L(XtVaCreateManagedWidget("meswinlabel", labelWidgetClass
,
153 meswin_viewport
= XtVaCreateManagedWidget("meswinviewport",
158 meswin_list
= XtVaCreateManagedWidget("meswinlist",
162 (XtArgVal
)dummy_message_list
,
165 meswin_close_command
=
166 I_L(XtVaCreateManagedWidget("meswinclosecommand", commandWidgetClass
,
169 meswin_goto_command
=
170 I_L(XtVaCreateManagedWidget("meswingotocommand", commandWidgetClass
,
175 meswin_popcity_command
=
176 I_L(XtVaCreateManagedWidget("meswinpopcitycommand", commandWidgetClass
,
181 XtAddCallback(meswin_list
, XtNcallback
, meswin_list_callback
,
184 XtAddCallback(meswin_close_command
, XtNcallback
, meswin_close_callback
,
187 XtAddCallback(meswin_goto_command
, XtNcallback
, meswin_goto_callback
,
190 XtAddCallback(meswin_popcity_command
, XtNcallback
, meswin_popcity_callback
,
193 real_meswin_dialog_update();
195 XtRealizeWidget(meswin_dialog_shell
);
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()"));
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 **************************************************************************/
214 static void meswin_scroll_down(void)
219 if (!meswin_dialog_shell
|| creating
) {
222 if (meswin_get_num_messages() <= N_MSG_VIEW
) {
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
);
232 /**************************************************************************
234 **************************************************************************/
235 void real_meswin_dialog_update(void)
237 Dimension height
, iheight
, width
, oldheight
, newheight
;
238 int i
, num
= meswin_get_num_messages();
240 XawFormDoLayout(meswin_form
, False
);
242 XtVaGetValues(meswin_viewport
, XtNheight
, &oldheight
, NULL
);
245 XawListChange(meswin_list
, dummy_message_list
, 1, 0, True
);
247 /* strings will not be freed */
248 static char **strings
= NULL
;
250 strings
= fc_realloc(strings
, num
* sizeof(char *));
252 for (i
= 0; i
< num
; i
++) {
253 strings
[i
] = meswin_get_message(i
)->descr
;
256 XawListChange(meswin_list
, strings
, num
, 0, True
);
259 /* Much of the following copied from city_report_dialog_update() */
260 XtVaGetValues(meswin_list
, XtNlongest
, &i
, NULL
);
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
);
267 /* Seems have to do this here so we get the correct height below. */
268 XawFormDoLayout(meswin_form
, True
);
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
);
275 XtVaGetValues(meswin_form
, XtNheight
, &newheight
, NULL
);
276 newheight
= newheight
+ height
- oldheight
;
277 XtVaSetValues(meswin_form
, XtNheight
, newheight
, NULL
);
280 XtVaGetValues(meswin_list
, XtNheight
, &height
, NULL
);
281 XtVaGetValues(meswin_list
, XtNinternalHeight
, &iheight
, NULL
);
282 height
-= (iheight
* 2);
284 height
*= N_MSG_VIEW
;
285 height
+= (iheight
* 2);
286 if (height
!= oldheight
) {
287 if (oldheight
== 0) {
288 XtVaSetValues(meswin_viewport
, XtNheight
, height
, NULL
);
290 XtVaGetValues(meswin_form
, XtNheight
, &newheight
, NULL
);
291 newheight
= newheight
+ height
- oldheight
;
292 XtVaSetValues(meswin_form
, XtNheight
, newheight
, NULL
);
295 meswin_scroll_down();
298 XtSetSensitive(meswin_goto_command
, FALSE
);
299 XtSetSensitive(meswin_popcity_command
, FALSE
);
302 /**************************************************************************
304 **************************************************************************/
305 static void meswin_list_callback(Widget w
, XtPointer client_data
,
308 XawListReturnStruct
*ret
= XawListShowCurrent(meswin_list
);
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
);
314 XtSetSensitive(meswin_goto_command
, message
->location_ok
? True
: False
);
315 XtSetSensitive(meswin_popcity_command
, message
->city_ok
? True
: False
);
317 XtSetSensitive(meswin_goto_command
, False
);
318 XtSetSensitive(meswin_popcity_command
, False
);
322 /**************************************************************************
324 **************************************************************************/
325 static void meswin_close_callback(Widget w
, XtPointer client_data
,
328 meswin_dialog_popdown();
331 /****************************************************************
333 *****************************************************************/
334 void meswin_msg_close(Widget w
)
336 meswin_close_callback(w
, NULL
, NULL
);
339 /**************************************************************************
341 **************************************************************************/
342 static void meswin_goto_callback(Widget w
, XtPointer client_data
,
345 XawListReturnStruct
*ret
= XawListShowCurrent(meswin_list
);
347 if (ret
->list_index
!= XAW_LIST_NONE
) {
348 meswin_goto(ret
->list_index
);
352 /**************************************************************************
354 **************************************************************************/
355 static void meswin_popcity_callback(Widget w
, XtPointer client_data
,
358 XawListReturnStruct
*ret
= XawListShowCurrent(meswin_list
);
360 if (ret
->list_index
!= XAW_LIST_NONE
) {
361 meswin_popup_city(ret
->list_index
);