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 /***********************************************************************
15                           chatline.c  -  description
16                              -------------------
17     begin                : Sun Jun 30 2002
18     copyright            : (C) 2002 by Rafał Bursig
19     email                : Rafał Bursig <bursig@poczta.fm>
20 ***********************************************************************/
21 
22 #ifdef HAVE_CONFIG_H
23 #include <fc_config.h>
24 #endif
25 
26 /* SDL2 */
27 #ifdef SDL2_PLAIN_INCLUDE
28 #include <SDL.h>
29 #else  /* SDL2_PLAIN_INCLUDE */
30 #include <SDL2/SDL.h>
31 #endif /* SDL2_PLAIN_INCLUDE */
32 
33 /* utility */
34 #include "fcintl.h"
35 #include "log.h"
36 
37 /* common */
38 #include "game.h"
39 #include "packets.h"
40 
41 /* client */
42 #include "client_main.h"
43 #include "clinet.h"
44 #include "connectdlg_common.h"
45 
46 /* gui-sdl2 */
47 #include "colors.h"
48 #include "dialogs.h"
49 #include "graphics.h"
50 #include "gui_iconv.h"
51 #include "gui_id.h"
52 #include "gui_main.h"
53 #include "gui_tilespec.h"
54 #include "mapview.h"
55 #include "messagewin.h"
56 #include "pages.h"
57 #include "themespec.h"
58 #include "unistring.h"
59 #include "utf8string.h"
60 #include "widget.h"
61 
62 #include "chatline.h"
63 
64 #define PTSIZE_LOG_FONT adj_font(10)
65 
66 struct CONNLIST {
67   struct ADVANCED_DLG *pUsers_Dlg;
68   struct ADVANCED_DLG *pChat_Dlg;
69   struct widget *pBeginWidgetList;
70   struct widget *pEndWidgetList;
71   struct widget *pStartButton;
72   struct widget *pSelectNationButton;
73   struct widget *pLoadGameButton;
74   struct widget *pConfigure;
75   struct widget *pBackButton;
76   struct widget *pEdit;
77   int text_width;
78   int active;
79 } *pConnDlg = NULL;
80 
81 static void popup_conn_list_dialog(void);
82 static void add_to_chat_list(char *msg, size_t n_alloc);
83 
84 /**************************************************************************
85                                   LOAD GAME
86 **************************************************************************/
87 
88 struct ADVANCED_DLG *pLoadDialog;
89 
90 /**************************************************************************
91   User event to load game dialog window.
92 **************************************************************************/
move_load_game_dlg_callback(struct widget * pWindow)93 static int move_load_game_dlg_callback(struct widget *pWindow)
94 {
95   if (PRESSED_EVENT(Main.event)) {
96     move_window_group(pLoadDialog->pBeginWidgetList, pWindow);
97   }
98 
99   return -1;
100 }
101 
102 /**************************************************************************
103   Close load game dialog
104 **************************************************************************/
popdown_load_game_dialog(void)105 void popdown_load_game_dialog(void)
106 {
107   if (pLoadDialog) {
108     popdown_window_group_dialog(pLoadDialog->pBeginWidgetList, pLoadDialog->pEndWidgetList);
109     FC_FREE(pLoadDialog->pScroll);
110     FC_FREE(pLoadDialog);
111 
112     /* enable buttons */
113     set_wstate(pConnDlg->pBackButton, FC_WS_NORMAL);
114     widget_redraw(pConnDlg->pBackButton);
115     widget_mark_dirty(pConnDlg->pBackButton);
116     set_wstate(pConnDlg->pLoadGameButton, FC_WS_NORMAL);
117     widget_redraw(pConnDlg->pLoadGameButton);
118     widget_mark_dirty(pConnDlg->pLoadGameButton);
119     set_wstate(pConnDlg->pStartButton, FC_WS_NORMAL);
120     widget_redraw(pConnDlg->pStartButton);
121     widget_mark_dirty(pConnDlg->pStartButton);
122 
123     flush_dirty();
124   }
125 }
126 
127 /**************************************************************************
128   User clicked load game dialog close-button.
129 **************************************************************************/
exit_load_dlg_callback(struct widget * pWidget)130 static int exit_load_dlg_callback(struct widget *pWidget)
131 {
132   if (PRESSED_EVENT(Main.event)) {
133     if (get_client_page() == PAGE_LOAD) {
134       set_client_page(PAGE_START);
135     } else {
136       popdown_load_game_dialog();
137     }
138   }
139 
140   return -1;
141 }
142 
143 /**************************************************************************
144   User selected file to load.
145 **************************************************************************/
load_selected_game_callback(struct widget * pWidget)146 static int load_selected_game_callback(struct widget *pWidget)
147 {
148   if (PRESSED_EVENT(Main.event)) {
149     char *filename = (char*)pWidget->data.ptr;
150 
151     if (is_server_running()) {
152       send_chat_printf("/load %s", filename);
153 
154       if (get_client_page() == PAGE_LOAD) {
155         set_client_page(PAGE_START);
156       } else if (get_client_page() == PAGE_START) {
157         popdown_load_game_dialog();
158       }
159     } else {
160       set_client_page(PAGE_MAIN);
161     }
162   }
163 
164   return -1;
165 }
166 
167 /**************************************************************************
168   Open load game dialog
169 **************************************************************************/
popup_load_game_dialog(void)170 static void popup_load_game_dialog(void)
171 {
172   struct widget *pWindow;
173   struct widget *pCloseButton;
174   struct widget *pFilenameLabel = NULL;
175   struct widget *pFirstLabel = NULL;
176   struct widget *pLastLabel = NULL;
177   struct widget *pNextLabel = NULL;
178   utf8_str *title, *filename;
179   SDL_Rect area;
180   struct fileinfo_list *files;
181   int count = 0;
182   int scrollbar_width = 0;
183   int max_label_width = 0;
184 
185   if (pLoadDialog) {
186     return;
187   }
188 
189   /* disable buttons */
190   set_wstate(pConnDlg->pBackButton, FC_WS_DISABLED);
191   widget_redraw(pConnDlg->pBackButton);
192   widget_mark_dirty(pConnDlg->pBackButton);
193   set_wstate(pConnDlg->pLoadGameButton, FC_WS_DISABLED);
194   widget_redraw(pConnDlg->pLoadGameButton);
195   widget_mark_dirty(pConnDlg->pLoadGameButton);
196   set_wstate(pConnDlg->pSelectNationButton, FC_WS_DISABLED);
197   widget_redraw(pConnDlg->pSelectNationButton);
198   widget_mark_dirty(pConnDlg->pSelectNationButton);
199   set_wstate(pConnDlg->pStartButton, FC_WS_DISABLED);
200   widget_redraw(pConnDlg->pStartButton);
201   widget_mark_dirty(pConnDlg->pStartButton);
202 
203   /* create dialog */
204   pLoadDialog = fc_calloc(1, sizeof(struct ADVANCED_DLG));
205 
206   title = create_utf8_from_char(_("Choose Saved Game to Load"), adj_font(12));
207   title->style |= TTF_STYLE_BOLD;
208 
209   pWindow = create_window_skeleton(NULL, title, 0);
210   pWindow->action = move_load_game_dlg_callback;
211   set_wstate(pWindow, FC_WS_NORMAL);
212 
213   add_to_gui_list(ID_WINDOW, pWindow);
214 
215   pLoadDialog->pEndWidgetList = pWindow;
216 
217   area = pWindow->area;
218 
219   /* close button */
220   pCloseButton = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
221                                   WF_WIDGET_HAS_INFO_LABEL
222                                   | WF_RESTORE_BACKGROUND);
223   pCloseButton->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
224                                                    adj_font(12));
225   pCloseButton->action = exit_load_dlg_callback;
226   set_wstate(pCloseButton, FC_WS_NORMAL);
227   pCloseButton->key = SDLK_ESCAPE;
228 
229   add_to_gui_list(ID_BUTTON, pCloseButton);
230 
231   area.w += pCloseButton->size.w;
232 
233   pLoadDialog->pBeginWidgetList = pCloseButton;
234 
235   /* create scrollbar */
236   scrollbar_width = create_vertical_scrollbar(pLoadDialog, 1, 20, TRUE, TRUE);
237   hide_scrollbar(pLoadDialog->pScroll);
238 
239   /* search for user saved games. */
240   files = fileinfolist_infix(get_save_dirs(), ".sav", FALSE);
241   fileinfo_list_iterate(files, pfile) {
242     count++;
243 
244     filename = create_utf8_from_char(pfile->name, adj_font(13));
245     filename->style |= SF_CENTER;
246     pFilenameLabel = create_iconlabel(NULL, pWindow->dst, filename,
247       (WF_FREE_DATA | WF_SELECT_WITHOUT_BAR | WF_RESTORE_BACKGROUND));
248 
249     /* store filename */
250     pFilenameLabel->data.ptr = fc_calloc(1, strlen(pfile->fullname) + 1);
251     fc_strlcpy((char*)pFilenameLabel->data.ptr, pfile->fullname, strlen(pfile->fullname) + 1);
252 
253     pFilenameLabel->action = load_selected_game_callback;
254 
255     set_wstate(pFilenameLabel, FC_WS_NORMAL);
256 
257     /* FIXME: this was supposed to be add_widget_to_vertical_scroll_widget_list(), but
258      * add_widget_to_vertical_scroll_widget_list() needs the scrollbar area to be defined
259      * for updating the scrollbar position, but the area is not known yet (depends on
260      * maximum label width) */
261     add_to_gui_list(ID_LABEL, pFilenameLabel);
262 
263     if (count == 1) {
264       pFirstLabel = pFilenameLabel;
265     }
266 
267     max_label_width = MAX(max_label_width, pFilenameLabel->size.w);
268   } fileinfo_list_iterate_end;
269   fileinfo_list_destroy(files);
270 
271   pLastLabel = pFilenameLabel;
272 
273   area.w = MAX(area.w, max_label_width + scrollbar_width + 1);
274 
275   if (count > 0) {
276     area.h = (pLoadDialog->pScroll->active * pFilenameLabel->size.h) + adj_size(5);
277   }
278 
279   resize_window(pWindow, theme_get_background(theme, BACKGROUND_LOADGAMEDLG),
280                 NULL,
281                 (pWindow->size.w - pWindow->area.w) + area.w,
282                 (pWindow->size.h - pWindow->area.h) + area.h);
283 
284   area = pWindow->area;
285 
286   setup_vertical_scrollbar_area(pLoadDialog->pScroll,
287                                 area.x + area.w - 1,
288                                 area.y + 1,
289                                 area.h - adj_size(2), TRUE);
290 
291   /* add filename labels to list */
292   pFilenameLabel = pFirstLabel;
293   while (pFilenameLabel) {
294     pFilenameLabel->size.w = area.w - scrollbar_width - 3;
295 
296     pNextLabel = pFilenameLabel->prev;
297 
298     del_widget_pointer_from_gui_list(pFilenameLabel);
299     if (pFilenameLabel == pFirstLabel) {
300       add_widget_to_vertical_scroll_widget_list(pLoadDialog,
301           pFilenameLabel, pCloseButton,
302           FALSE,
303           area.x + 1,
304           area.y + adj_size(2));
305     } else {
306       add_widget_to_vertical_scroll_widget_list(pLoadDialog,
307           pFilenameLabel,
308           pLoadDialog->pBeginActiveWidgetList,
309           FALSE,
310           area.x + 1,
311           area.y + adj_size(2));
312     }
313 
314     if (pFilenameLabel == pLastLabel) {
315       break;
316     }
317 
318     pFilenameLabel = pNextLabel;
319   }
320 
321   widget_set_position(pWindow,
322                       (main_window_width() - pWindow->size.w) / 2,
323                       (main_window_height() - pWindow->size.h) / 2);
324 
325   widget_set_position(pCloseButton,
326                       area.x + area.w - pCloseButton->size.w - 1,
327                       pWindow->size.y + adj_size(2));
328 
329   /* FIXME: the scrollbar already got a background saved in
330    * add_widget_to_vertical_scroll_widget_list(), but the window
331    * is not drawn yet, so this saved background is wrong.
332    * Deleting it here as a workaround. */
333   FREESURFACE(pLoadDialog->pScroll->pScrollBar->gfx);
334 
335   redraw_group(pLoadDialog->pBeginWidgetList, pWindow, 1);
336   flush_dirty();
337 }
338 
339 /**************************************************************************
340   Sent msg/command from input dlg to server
341 **************************************************************************/
inputline_return_callback(struct widget * pWidget)342 static int inputline_return_callback(struct widget *pWidget)
343 {
344   if (Main.event.type == SDL_KEYDOWN
345       && (Main.event.key.keysym.sym == SDLK_RETURN
346           || Main.event.key.keysym.sym == SDLK_KP_ENTER)) {
347 
348     if (pWidget->string_utf8->text == NULL) {
349       return -1;
350     }
351 
352     if (pWidget->string_utf8->text[0] != '\0') {
353       send_chat(pWidget->string_utf8->text);
354 
355       output_window_append(ftc_any, pWidget->string_utf8->text);
356     }
357   }
358 
359   return -1;
360 }
361 
362 /**************************************************************************
363   This function is main chat/command client input.
364 **************************************************************************/
popup_input_line(void)365 void popup_input_line(void)
366 {
367   struct widget *pInput_Edit;
368 
369   pInput_Edit = create_edit_from_chars(NULL, Main.gui, "", adj_font(12),
370                                        adj_size(400), 0);
371 
372   pInput_Edit->size.x = (main_window_width() - pInput_Edit->size.w) / 2;
373   pInput_Edit->size.y = (main_window_height() - pInput_Edit->size.h) / 2;
374 
375   if (edit(pInput_Edit) != ED_ESC) {
376     inputline_return_callback(pInput_Edit);
377   }
378 
379   widget_undraw(pInput_Edit);
380   widget_mark_dirty(pInput_Edit);
381   FREEWIDGET(pInput_Edit);
382 
383   flush_dirty();
384 }
385 
386 /**************************************************************************
387   Appends the string to the chat output window.  The string should be
388   inserted on its own line, although it will have no newline.
389 **************************************************************************/
real_output_window_append(const char * astring,const struct text_tag_list * tags,int conn_id)390 void real_output_window_append(const char *astring,
391                                const struct text_tag_list *tags,
392                                int conn_id)
393 {
394   /* Currently this is a wrapper to the message subsystem. */
395   if (pConnDlg) {
396     size_t n = strlen(astring);
397     char *buffer = fc_strdup(astring);
398 
399     add_to_chat_list(buffer, n);
400   } else {
401     meswin_add(astring, tags, NULL, E_CHAT_MSG);
402   }
403 }
404 
405 /**************************************************************************
406   Get the text of the output window, and call write_chatline_content() to
407   log it.
408 **************************************************************************/
log_output_window(void)409 void log_output_window(void)
410 {
411   /* TODO */
412 }
413 
414 /**************************************************************************
415   Clear all text from the output window.
416 **************************************************************************/
clear_output_window(void)417 void clear_output_window(void)
418 {
419   /* TODO */
420 }
421 
422 /* ====================================================================== */
423 
424 /**************************************************************************
425   User did something to connection list dialog.
426 **************************************************************************/
conn_dlg_callback(struct widget * pWindow)427 static int conn_dlg_callback(struct widget *pWindow)
428 {
429   return -1;
430 }
431 
432 /**************************************************************************
433   User selected to get back from connection list dialog.
434 **************************************************************************/
disconnect_conn_callback(struct widget * pWidget)435 static int disconnect_conn_callback(struct widget *pWidget)
436 {
437   if (PRESSED_EVENT(Main.event)) {
438     popdown_conn_list_dialog();
439     flush_dirty();
440     disconnect_from_server();
441   }
442 
443   return -1;
444 }
445 
446 /**************************************************************************
447   Handle chat messages when connection dialog open.
448 **************************************************************************/
add_to_chat_list(char * msg,size_t n_alloc)449 static void add_to_chat_list(char *msg, size_t n_alloc)
450 {
451   utf8_str *pstr;
452   struct widget *pBuf, *pWindow = pConnDlg->pEndWidgetList;
453 
454   fc_assert_ret(msg != NULL);
455   fc_assert_ret(n_alloc != 0);
456 
457   pstr = create_utf8_str(msg, n_alloc, adj_font(12));
458 
459   if (convert_utf8_str_to_const_surface_width(pstr, pConnDlg->text_width - adj_size(5))) {
460     utf8_str *pstr2;
461     int count = 0;
462     char **utf8_texts = create_new_line_utf8strs(pstr->text);
463 
464     while (utf8_texts[count] != NULL) {
465       pstr2 = create_utf8_str(utf8_texts[count],
466                               strlen(utf8_texts[count]) + 1, adj_font(12));
467       pstr2->bgcol = (SDL_Color) {0, 0, 0, 0};
468       pBuf = create_themelabel2(NULL, pWindow->dst,
469                                 pstr2, pConnDlg->text_width, 0,
470                                 (WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
471 
472       pBuf->size.w = pConnDlg->text_width;
473       add_widget_to_vertical_scroll_widget_list(pConnDlg->pChat_Dlg, pBuf,
474                         pConnDlg->pChat_Dlg->pBeginActiveWidgetList, FALSE,
475                         pWindow->size.x + adj_size(10 + 60 + 10),
476                         pWindow->size.y + adj_size(14));
477       count++;
478     }
479     redraw_group(pConnDlg->pChat_Dlg->pBeginWidgetList,
480                  pConnDlg->pChat_Dlg->pEndWidgetList, TRUE);
481     FREEUTF8STR(pstr);
482   } else {
483     pstr->bgcol = (SDL_Color) {0, 0, 0, 0};
484     pBuf = create_themelabel2(NULL, pWindow->dst,
485                               pstr, pConnDlg->text_width, 0,
486                               (WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
487 
488     pBuf->size.w = pConnDlg->text_width;
489 
490     if (add_widget_to_vertical_scroll_widget_list(pConnDlg->pChat_Dlg, pBuf,
491                         pConnDlg->pChat_Dlg->pBeginActiveWidgetList, FALSE,
492                         pWindow->size.x + adj_size(10 + 60 + 10),
493                         pWindow->size.y + adj_size(14))) {
494       redraw_group(pConnDlg->pChat_Dlg->pBeginWidgetList,
495                    pConnDlg->pChat_Dlg->pEndWidgetList, TRUE);
496     } else {
497       widget_redraw(pBuf);
498       widget_mark_dirty(pBuf);
499     }
500   }
501 
502   flush_dirty();
503 }
504 
505 /**************************************************************************
506   User interacted with connection dialog input field.
507 **************************************************************************/
input_edit_conn_callback(struct widget * pWidget)508 static int input_edit_conn_callback(struct widget *pWidget)
509 {
510   if (Main.event.type == SDL_KEYDOWN
511       && (Main.event.key.keysym.sym == SDLK_RETURN
512           || Main.event.key.keysym.sym == SDLK_KP_ENTER)) {
513     if (pWidget->string_utf8->text != NULL) {
514       if (pWidget->string_utf8->text[0] != '\0') {
515         send_chat(pWidget->string_utf8->text);
516       }
517 
518       free(pWidget->string_utf8->text);
519       pWidget->string_utf8->text = fc_malloc(1);
520       pWidget->string_utf8->n_alloc = 0;
521     }
522   }
523 
524   return -1;
525 }
526 
527 /**************************************************************************
528    User interacted with Start Game button.
529 **************************************************************************/
start_game_callback(struct widget * pWidget)530 static int start_game_callback(struct widget *pWidget)
531 {
532   if (PRESSED_EVENT(Main.event)) {
533     send_chat("/start");
534   }
535 
536   return -1;
537 }
538 
539 /**************************************************************************
540   User interacted with Select Nation button.
541 **************************************************************************/
select_nation_callback(struct widget * pWidget)542 static int select_nation_callback(struct widget *pWidget)
543 {
544   if (PRESSED_EVENT(Main.event)) {
545     popup_races_dialog(client.conn.playing);
546   }
547 
548   return -1;
549 }
550 
551 /* not implemented yet */
552 #if 0
553 /**************************************************************************
554   User interacted with Server Settings button.
555 **************************************************************************/
556 static int server_config_callback(struct widget *pWidget)
557 {
558   return -1;
559 }
560 #endif
561 
562 /**************************************************************************
563   User interacted with Load Game button.
564 **************************************************************************/
load_game_callback(struct widget * pWidget)565 static int load_game_callback(struct widget *pWidget)
566 {
567   if (PRESSED_EVENT(Main.event)) {
568     /* set_wstate(pConnDlg->pLoadGameButton, FC_WS_NORMAL);
569      * widget_redraw(pConnDlg->pLoadGameButton);
570      * flush_dirty(); */
571     popup_load_game_dialog();
572   }
573 
574   return -1;
575 }
576 
577 /**************************************************************************
578   Update the connected users list at pregame state.
579 **************************************************************************/
real_conn_list_dialog_update(void * unused)580 void real_conn_list_dialog_update(void *unused)
581 {
582   if (C_S_PREPARING == client_state()) {
583     if (pConnDlg) {
584       struct widget *pBuf = NULL, *pWindow = pConnDlg->pEndWidgetList;
585       utf8_str *pstr = create_utf8_str(NULL, 0, adj_font(12));
586       bool create;
587 
588       pstr->bgcol = (SDL_Color) {0, 0, 0, 0};
589 
590       if (pConnDlg->pUsers_Dlg) {
591         del_group(pConnDlg->pUsers_Dlg->pBeginActiveWidgetList,
592                   pConnDlg->pUsers_Dlg->pEndActiveWidgetList);
593         pConnDlg->pUsers_Dlg->pActiveWidgetList = NULL;
594         pConnDlg->pUsers_Dlg->pBeginWidgetList =
595           pConnDlg->pUsers_Dlg->pScroll->pScrollBar;
596         pConnDlg->pUsers_Dlg->pScroll->count = 0;
597       } else {
598         pConnDlg->pUsers_Dlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
599         pConnDlg->pUsers_Dlg->pEndWidgetList = pConnDlg->pBeginWidgetList;
600         pConnDlg->pUsers_Dlg->pBeginWidgetList = pConnDlg->pBeginWidgetList;
601 
602         create_vertical_scrollbar(pConnDlg->pUsers_Dlg, 1,
603                                   pConnDlg->active, TRUE, TRUE);
604         pConnDlg->pUsers_Dlg->pEndWidgetList =
605           pConnDlg->pUsers_Dlg->pEndWidgetList->prev;
606         setup_vertical_scrollbar_area(pConnDlg->pUsers_Dlg->pScroll,
607           pWindow->size.x + pWindow->size.w - adj_size(30),
608           pWindow->size.y + adj_size(14), pWindow->size.h - adj_size(44) - adj_size(40), FALSE);
609       }
610 
611       hide_scrollbar(pConnDlg->pUsers_Dlg->pScroll);
612       create = TRUE;
613       conn_list_iterate(game.est_connections, pconn) {
614         copy_chars_to_utf8_str(pstr, pconn->username);
615 
616         pBuf = create_themelabel2(NULL, pWindow->dst, pstr, adj_size(100), 0,
617                 (WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
618         clear_wflag(pBuf, WF_FREE_STRING);
619 
620         pBuf->ID = ID_LABEL;
621 
622         /* add to widget list */
623         if (create) {
624           add_widget_to_vertical_scroll_widget_list(pConnDlg->pUsers_Dlg,
625             pBuf, pConnDlg->pUsers_Dlg->pBeginWidgetList, FALSE,
626             pWindow->area.x + pWindow->area.w - adj_size(130),
627             pWindow->size.y + adj_size(14));
628           create = FALSE;
629         } else {
630 	  add_widget_to_vertical_scroll_widget_list(pConnDlg->pUsers_Dlg,
631                 pBuf, pConnDlg->pUsers_Dlg->pBeginActiveWidgetList, FALSE,
632                 pWindow->area.x + pWindow->area.w - adj_size(130),
633                 pWindow->size.y + adj_size(14));
634         }
635       } conn_list_iterate_end;
636 
637       pConnDlg->pBeginWidgetList = pConnDlg->pUsers_Dlg->pBeginWidgetList;
638       FREEUTF8STR(pstr);
639 
640 /* FIXME: implement the server settings dialog and then reactivate this part */
641 #if 0
642       if (ALLOW_CTRL == client.conn.access_level
643           || ALLOW_HACK == client.conn.access_level) {
644         set_wstate(pConnDlg->pConfigure, FC_WS_NORMAL);
645       } else {
646         set_wstate(pConnDlg->pConfigure, FC_WS_DISABLED);
647       }
648 #endif
649 
650       /* redraw */
651       redraw_group(pConnDlg->pBeginWidgetList, pConnDlg->pEndWidgetList, 0);
652 
653       widget_flush(pConnDlg->pEndWidgetList);
654     } else {
655       popup_conn_list_dialog();
656     }
657 
658     /* PAGE_LOAD -> the server was started from the main page to load a game */
659     if (get_client_page() == PAGE_LOAD) {
660       popup_load_game_dialog();
661     }
662   } else {
663     if (popdown_conn_list_dialog()) {
664       flush_dirty();
665     }
666   }
667 }
668 
669 /**************************************************************************
670   Open connection list dialog
671 **************************************************************************/
popup_conn_list_dialog(void)672 static void popup_conn_list_dialog(void)
673 {
674   SDL_Color window_bg_color = {255, 255, 255, 96};
675 
676   struct widget *pWindow = NULL, *pBuf = NULL, *pLabel = NULL;
677   struct widget* pBackButton = NULL;
678   struct widget *pStartGameButton = NULL;
679   struct widget *pSelectNationButton = NULL;
680 /*  struct widget *pServerSettingsButton = NULL;*/
681   utf8_str *pstr = NULL;
682   int n;
683   SDL_Rect area;
684   SDL_Surface *pSurf;
685 
686   if (pConnDlg || !client.conn.established) {
687     return;
688   }
689 
690   meswin_dialog_popdown();
691 
692   pConnDlg = fc_calloc(1, sizeof(struct CONNLIST));
693 
694   pWindow = create_window_skeleton(NULL, NULL, 0);
695   pWindow->action = conn_dlg_callback;
696   set_wstate(pWindow, FC_WS_NORMAL);
697   clear_wflag(pWindow, WF_DRAW_FRAME_AROUND_WIDGET);
698 
699   pConnDlg->pEndWidgetList = pWindow;
700   add_to_gui_list(ID_WINDOW, pWindow);
701 
702   widget_set_position(pWindow, 0, 0);
703 
704   /* create window background */
705   pSurf = theme_get_background(theme, BACKGROUND_CONNLISTDLG);
706   if (resize_window(pWindow, pSurf, NULL, main_window_width(), main_window_height())) {
707     FREESURFACE(pSurf);
708   }
709 
710   pConnDlg->text_width = pWindow->size.w - adj_size(130) - adj_size(20) - adj_size(20);
711 
712   /* chat area background */
713   area.x = adj_size(10);
714   area.y = adj_size(14);
715   area.w = pConnDlg->text_width + adj_size(20);
716   area.h = pWindow->size.h - adj_size(44) - adj_size(40);
717   fill_rect_alpha(pWindow->theme, &area, &window_bg_color);
718 
719   create_frame(pWindow->theme,
720                area.x - 1, area.y - 1, area.w + 1, area.h + 1,
721                get_theme_color(COLOR_THEME_CONNLISTDLG_FRAME));
722 
723   /* user list background */
724   area.x = pWindow->size.w - adj_size(130);
725   area.y = adj_size(14);
726   area.w = adj_size(120);
727   area.h = pWindow->size.h - adj_size(44) - adj_size(40);
728   fill_rect_alpha(pWindow->theme, &area, &window_bg_color);
729 
730   create_frame(pWindow->theme,
731                area.x - 1, area.y - 1, area.w + 1, area.h + 1,
732                get_theme_color(COLOR_THEME_CONNLISTDLG_FRAME));
733 
734   draw_frame(pWindow->theme, 0, 0, pWindow->theme->w, pWindow->theme->h);
735 
736   /* -------------------------------- */
737 
738   /* chat area */
739 
740   pConnDlg->pChat_Dlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
741 
742   n = conn_list_size(game.est_connections);
743 
744   {
745     char cbuf[256];
746 
747     fc_snprintf(cbuf, sizeof(cbuf), _("Total users logged in : %d"), n);
748     pstr = create_utf8_from_char(cbuf, adj_font(12));
749   }
750 
751   pstr->bgcol = (SDL_Color) {0, 0, 0, 0};
752 
753   pLabel = create_themelabel2(NULL, pWindow->dst,
754                               pstr, pConnDlg->text_width, 0,
755                               (WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
756 
757   widget_set_position(pLabel, adj_size(10), adj_size(14));
758 
759   add_to_gui_list(ID_LABEL, pLabel);
760 
761   pConnDlg->pChat_Dlg->pBeginWidgetList = pLabel;
762   pConnDlg->pChat_Dlg->pEndWidgetList = pLabel;
763   pConnDlg->pChat_Dlg->pBeginActiveWidgetList = pConnDlg->pChat_Dlg->pBeginWidgetList;
764   pConnDlg->pChat_Dlg->pEndActiveWidgetList = pConnDlg->pChat_Dlg->pEndWidgetList;
765 
766   n = (pWindow->size.h - adj_size(44) - adj_size(40)) / pLabel->size.h;
767   pConnDlg->active = n;
768 
769   create_vertical_scrollbar(pConnDlg->pChat_Dlg, 1,
770                             pConnDlg->active, TRUE, TRUE);
771 
772   setup_vertical_scrollbar_area(pConnDlg->pChat_Dlg->pScroll,
773                 adj_size(10) + pConnDlg->text_width + 1,
774                 adj_size(14), pWindow->size.h - adj_size(44) - adj_size(40), FALSE);
775   hide_scrollbar(pConnDlg->pChat_Dlg->pScroll);
776 
777   /* -------------------------------- */
778 
779   /* input field */
780 
781   pBuf = create_edit_from_chars(NULL, pWindow->dst, "",
782                                 adj_font(12), pWindow->size.w - adj_size(10) - adj_size(10),
783                                 (WF_RESTORE_BACKGROUND|WF_EDIT_LOOP));
784 
785   pBuf->size.x = adj_size(10);
786   pBuf->size.y = pWindow->size.h - adj_size(40) - adj_size(5) - pBuf->size.h;
787   pBuf->action = input_edit_conn_callback;
788   set_wstate(pBuf, FC_WS_NORMAL);
789   pConnDlg->pEdit = pBuf;
790   add_to_gui_list(ID_EDIT, pBuf);
791 
792   /* buttons */
793 
794   pBuf = create_themeicon_button_from_chars(current_theme->BACK_Icon, pWindow->dst,
795                                             _("Back"), adj_font(12), 0);
796   pBuf->size.x = adj_size(10);
797   pBuf->size.y = pWindow->size.h - adj_size(10) - pBuf->size.h;
798   pConnDlg->pBackButton = pBuf;
799   pBuf->action = disconnect_conn_callback;
800   set_wstate(pBuf, FC_WS_NORMAL);
801   pBuf->key = SDLK_ESCAPE;
802   add_to_gui_list(ID_BUTTON, pBuf);
803   pBackButton = pBuf;
804 
805   pBuf = create_themeicon_button_from_chars(current_theme->OK_Icon, pWindow->dst,
806                                             _("Start"), adj_font(12), 0);
807   pBuf->size.x = pWindow->size.w - adj_size(10) - pBuf->size.w;
808   pBuf->size.y = pBackButton->size.y;
809   pConnDlg->pStartButton = pBuf;
810   pBuf->action = start_game_callback;
811   set_wstate(pBuf, FC_WS_NORMAL);
812   add_to_gui_list(ID_BUTTON, pBuf);
813   pStartGameButton = pBuf;
814 
815   pBuf = create_themeicon_button_from_chars(NULL, pWindow->dst,
816                                             _("Pick Nation"), adj_font(12), 0);
817   pBuf->size.h = pStartGameButton->size.h;
818   pBuf->size.x = pStartGameButton->size.x - adj_size(10) - pBuf->size.w;
819   pBuf->size.y = pStartGameButton->size.y;
820   pConnDlg->pSelectNationButton = pBuf;
821   pBuf->action = select_nation_callback;
822   set_wstate(pBuf, FC_WS_NORMAL);
823   add_to_gui_list(ID_BUTTON, pBuf);
824   pSelectNationButton = pBuf;
825 
826   pBuf = create_themeicon_button_from_chars(NULL, pWindow->dst,
827                                             _("Load Game"), adj_font(12), 0);
828   pBuf->size.h = pSelectNationButton->size.h;
829   pBuf->size.x = pSelectNationButton->size.x - adj_size(10) - pBuf->size.w;
830   pBuf->size.y = pSelectNationButton->size.y;
831   pConnDlg->pLoadGameButton = pBuf;
832   pBuf->action = load_game_callback;
833   set_wstate(pBuf, FC_WS_NORMAL);
834   add_to_gui_list(ID_BUTTON, pBuf);
835 
836   /* not implemented yet */
837 #if 0
838   pBuf = create_themeicon_button_from_chars(NULL, pWindow->dst,
839                                             _("Server Settings"),
840                                             adj_font(12), 0);
841   pBuf->size.h = pSelectNationButton->size.h;
842   pBuf->size.x = pSelectNationButton->size.x - adj_size(10) - pBuf->size.w;
843   pBuf->size.y = pSelectNationButton->size.y;
844   pConnDlg->pConfigure = pBuf;
845   pBuf->action = server_config_callback;
846   set_wstate(pBuf, FC_WS_DISABLED);
847   add_to_gui_list(ID_BUTTON, pBuf);
848   pServerSettingsButton = pBuf;
849 #endif
850 
851   /* not implemented yet */
852 #if 0
853   pBuf = create_themeicon_button_from_chars(NULL, pWindow->dst->surface,
854                                             "?", adj_font(12), 0);
855   pBuf->size.y = pWindow->size.y + pWindow->size.h - (pBuf->size.h + 7);
856   pBuf->size.x = pWindow->size.x + pWindow->size.w - (pBuf->size.w + 10) - 5;
857 
858   pBuf->action = client_config_callback;
859   set_wstate(pBuf, FC_WS_NORMAL);
860   add_to_gui_list(ID_BUTTON, pBuf);
861 #endif
862 
863   pConnDlg->pBeginWidgetList = pBuf;
864   /* ------------------------------------------------------------ */
865 
866   conn_list_dialog_update();
867 }
868 
869 /**************************************************************************
870   Close connection list dialog.
871 **************************************************************************/
popdown_conn_list_dialog(void)872 bool popdown_conn_list_dialog(void)
873 {
874   if (pConnDlg) {
875     if (get_wstate(pConnDlg->pEdit) == FC_WS_PRESSED) {
876       force_exit_from_event_loop();
877     }
878 
879     popdown_window_group_dialog(pConnDlg->pBeginWidgetList,
880                                 pConnDlg->pEndWidgetList);
881     if (pConnDlg->pUsers_Dlg) {
882       FC_FREE(pConnDlg->pUsers_Dlg->pScroll);
883       FC_FREE(pConnDlg->pUsers_Dlg);
884     }
885 
886     if (pConnDlg->pChat_Dlg) {
887       FC_FREE(pConnDlg->pChat_Dlg->pScroll);
888       FC_FREE(pConnDlg->pChat_Dlg);
889     }
890 
891     FC_FREE(pConnDlg);
892 
893     return TRUE;
894   }
895 
896   return FALSE;
897 }
898 
899 /**************************************************************************
900   Got version message from metaserver thread.
901 **************************************************************************/
version_message(const char * vertext)902 void version_message(const char *vertext)
903 {
904   output_window_append(ftc_client, vertext);
905 }
906