2018-11-10 21:13:06 +05:00
// URTrator - Urban Terror server browser and game launcher, written in
2016-10-04 15:42:36 +05:00
// Go.
//
2019-12-29 13:21:05 +05:00
// Copyright (c) 2016-2020, Stanslav N. a.k.a pztrn (or p0z1tr0n) and
2018-11-10 21:13:06 +05:00
// URTrator contributors.
2016-10-04 15:42:36 +05:00
//
2018-11-10 21:13:06 +05:00
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2016-10-04 15:42:36 +05:00
package ui
import (
2018-11-10 13:21:53 +05:00
// stdlib
"fmt"
"runtime"
"sort"
"strconv"
"strings"
2016-10-04 15:42:36 +05:00
2018-11-10 13:21:53 +05:00
// Local
2019-12-29 13:21:05 +05:00
"go.dev.pztrn.name/urtrator/datamodels"
"go.dev.pztrn.name/urtrator/ioq3dataparser"
2016-10-04 15:42:36 +05:00
2018-11-10 13:21:53 +05:00
// Other
"github.com/mattn/go-gtk/gdkpixbuf"
"github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/gtk"
2016-10-04 15:42:36 +05:00
)
type MainWindow struct {
2018-11-10 13:21:53 +05:00
// Gamemodes.
gamemodes map [ string ] string
2016-10-04 15:42:36 +05:00
2018-11-10 13:21:53 +05:00
text string
2016-10-10 19:16:51 +05:00
2018-11-10 13:21:53 +05:00
// Widgets.
// The window itself.
window * gtk . Window
// Vertical Box.
vbox * gtk . VBox
// Main menu.
menubar * gtk . MenuBar
// Toolbar
toolbar * gtk . Toolbar
// Horizontal box for main window.
hpane * gtk . HPaned
// Tab widget.
tab_widget * gtk . Notebook
// Tabs list.
tabs map [ string ] * gtk . Frame
// All servers widget.
all_servers * gtk . TreeView
// Favorite servers widget.
fav_servers * gtk . TreeView
// Statusbar.
statusbar * gtk . Statusbar
// Statusbar context ID.
statusbar_context_id uint
// Profiles combobox.
profiles * gtk . ComboBoxText
// Checkbox for hiding/showing offline servers in 'Servers' tab list.
all_servers_hide_offline * gtk . CheckButton
// Checkbox for hiding/showing passworded servers in 'Servers' tab list.
all_servers_hide_private * gtk . CheckButton
// Combobox for filtering server's versions.
all_servers_version * gtk . ComboBoxText
// Combobox for filtering by gamemode.
all_servers_gamemode * gtk . ComboBoxText
// Checkbox for hiding/showing offline servers in 'Favorites' tab list.
fav_servers_hide_offline * gtk . CheckButton
// Checkbox for hiding/showing passworded servers in 'Favorites' tab list.
fav_servers_hide_private * gtk . CheckButton
// Combobox for filtering server's versions.
fav_servers_version * gtk . ComboBoxText
// Combobox for filtering by gamemode.
fav_servers_gamemode * gtk . ComboBoxText
// Game launch button.
launch_button * gtk . Button
// Server's main information.
server_info * gtk . TreeView
// Players information.
players_info * gtk . TreeView
// Quick connect: server address
qc_server_address * gtk . Entry
// Quick connect: password
qc_password * gtk . Entry
// Quick connect: nickname
qc_nickname * gtk . Entry
// Tray icon.
tray_icon * gtk . StatusIcon
// Tray menu.
tray_menu * gtk . Menu
// Toolbar's label.
toolbar_label * gtk . Label
2016-10-04 15:42:36 +05:00
2018-11-10 13:21:53 +05:00
// Storages.
// All servers store.
all_servers_store * gtk . ListStore
// All servers sortable store.
all_servers_store_sortable * gtk . TreeSortable
// Favorites
fav_servers_store * gtk . ListStore
// Server's information store.
server_info_store * gtk . ListStore
// Players information store.
players_info_store * gtk . ListStore
2016-10-04 15:42:36 +05:00
2018-11-10 13:21:53 +05:00
// Dialogs.
options_dialog * OptionsDialog
server_cvars_dialog * ServerCVarsDialog
2016-10-04 15:42:36 +05:00
2018-11-10 13:21:53 +05:00
// Other
// Old profiles count.
old_profiles_count int
// Window size.
window_width int
window_height int
// Window position.
window_pos_x int
window_pos_y int
// Main pane delimiter position. It is calculated like:
//
// window_width - pane_position
//
// so we will get same right pane width even if we will resize
// main window. On resize and restore it will be set like:
//
// window_width - m.pane_negative_position
pane_negative_position int
// Columns names for servers tabs.
column_names map [ string ] string
// Real columns positions on servers tabs.
column_pos map [ string ] map [ string ] int
2016-10-05 02:16:02 +05:00
2018-11-10 13:21:53 +05:00
// Resources.
// Pixbufs.
// For unavailable (e.g. offline) server.
server_offline_pic * gdkpixbuf . Pixbuf
// For online server.
server_online_pic * gdkpixbuf . Pixbuf
// For private (passworded) server.
server_private_pic * gdkpixbuf . Pixbuf
// For public server
server_public_pic * gdkpixbuf . Pixbuf
2016-10-07 22:21:19 +05:00
2018-11-10 13:21:53 +05:00
// Flags.
// Application is initialized?
initialized bool
// Window is hidden?
hidden bool
// Use other's tab information?
// Used when user changed active tab, to show information about
// server which is selected on activated tab.
use_other_servers_tab bool
// Does servers updating already in progress?
// This helps to prevent random crashes when more than one
// updating process in progress.
servers_already_updating bool
2016-10-04 15:42:36 +05:00
}
func ( m * MainWindow ) addToFavorites () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Adding server to favorites..." )
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
server_address := ""
if ! strings . Contains ( current_tab , ctx . Translator . Translate ( "Favorites" , nil )) {
server_address = m . getIpFromServersList ( current_tab )
}
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
// Getting server from database.
fd := & FavoriteDialog {}
if len ( server_address ) > 0 {
servers := [] datamodels . Server {}
address := strings . Split ( server_address , ":" )[ 0 ]
port := strings . Split ( server_address , ":" )[ 1 ]
err1 := ctx . Database . Db . Select ( & servers , ctx . Database . Db . Rebind ( "SELECT * FROM servers WHERE ip=? AND port=?" ), address , port )
if err1 != nil {
fmt . Println ( err1 . Error ())
}
fd . InitializeUpdate ( & servers [ 0 ])
} else {
fd . InitializeNew ()
}
2016-10-04 15:42:36 +05:00
}
2016-11-26 16:20:57 +05:00
func ( m * MainWindow ) allServersGamemodeFilterChanged () {
2018-11-10 13:21:53 +05:00
ctx . Cfg . Cfg [ "/serverslist/all_servers/gamemode" ] = strconv . Itoa ( m . all_servers_gamemode . GetActive ())
ctx . Eventer . LaunchEvent ( "loadAllServers" , nil )
2016-11-26 16:20:57 +05:00
}
2016-11-26 16:00:17 +05:00
func ( m * MainWindow ) allServersVersionFilterChanged () {
2018-11-10 13:21:53 +05:00
ctx . Cfg . Cfg [ "/serverslist/all_servers/version" ] = strconv . Itoa ( m . all_servers_version . GetActive ())
ctx . Eventer . LaunchEvent ( "loadAllServers" , nil )
2016-11-26 16:00:17 +05:00
}
2016-10-06 13:55:03 +05:00
// Executes when delimiter for two panes is moved, to calculate VALID
// position.
2016-10-05 02:16:02 +05:00
func ( m * MainWindow ) checkMainPanePosition () {
2018-11-10 13:21:53 +05:00
glib . IdleAdd ( func () bool {
m . pane_negative_position = m . window_width - m . hpane . GetPosition ()
return false
})
2016-10-05 02:16:02 +05:00
}
2016-10-06 13:55:03 +05:00
// Executes when main window is moved or resized.
// Also calculating pane delimiter position and set it to avoid
// widgets hell :).
2016-10-05 02:16:02 +05:00
func ( m * MainWindow ) checkPositionAndSize () {
2018-11-10 13:21:53 +05:00
glib . IdleAdd ( func () bool {
m . window_pos_x , m . window_pos_y = m . window . GetPosition ()
m . window_width , m . window_height = m . window . GetSize ()
2016-10-05 02:16:02 +05:00
2018-11-10 13:21:53 +05:00
m . hpane . SetPosition ( m . window_width - m . pane_negative_position )
return false
})
2016-10-05 02:16:02 +05:00
}
2016-10-06 13:55:03 +05:00
// Executes on URTrator shutdown.
2016-10-04 15:42:36 +05:00
func ( m * MainWindow ) Close () {
2018-11-10 13:21:53 +05:00
// Save window parameters.
ctx . Cfg . Cfg [ "/mainwindow/width" ] = strconv . Itoa ( m . window_width )
ctx . Cfg . Cfg [ "/mainwindow/height" ] = strconv . Itoa ( m . window_height )
ctx . Cfg . Cfg [ "/mainwindow/position_x" ] = strconv . Itoa ( m . window_pos_x )
ctx . Cfg . Cfg [ "/mainwindow/position_y" ] = strconv . Itoa ( m . window_pos_y )
ctx . Cfg . Cfg [ "/mainwindow/pane_negative_position" ] = strconv . Itoa ( m . pane_negative_position )
2016-10-05 02:16:02 +05:00
2018-11-10 13:21:53 +05:00
// Saving columns sizes and positions.
all_servers_columns := m . all_servers . GetColumns ()
for i := range all_servers_columns {
ctx . Cfg . Cfg [ "/mainwindow/all_servers/" + all_servers_columns [ i ]. GetTitle () + "_position" ] = strconv . Itoa ( i )
ctx . Cfg . Cfg [ "/mainwindow/all_servers/" + all_servers_columns [ i ]. GetTitle () + "_width" ] = strconv . Itoa ( all_servers_columns [ i ]. GetWidth ())
}
fav_servers_columns := m . fav_servers . GetColumns ()
for i := range fav_servers_columns {
ctx . Cfg . Cfg [ "/mainwindow/fav_servers/" + fav_servers_columns [ i ]. GetTitle () + "_position" ] = strconv . Itoa ( i )
ctx . Cfg . Cfg [ "/mainwindow/fav_servers/" + fav_servers_columns [ i ]. GetTitle () + "_width" ] = strconv . Itoa ( fav_servers_columns [ i ]. GetWidth ())
}
2016-10-07 21:14:48 +05:00
2018-11-10 13:21:53 +05:00
// Additional actions should be taken on Windows.
if runtime . GOOS == "windows" {
m . closeWin ()
}
2016-10-11 00:14:00 +05:00
2018-11-10 13:21:53 +05:00
ctx . Close ()
2016-10-04 15:42:36 +05:00
}
2016-10-12 19:23:10 +05:00
func ( m * MainWindow ) copyServerCredentialsToClipboard () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Copying server's credentials to clipboard..." )
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
server_address := m . getIpFromServersList ( current_tab )
ctx . Clipboard . CopyServerData ( server_address )
2016-10-12 19:23:10 +05:00
}
2016-10-06 13:55:03 +05:00
// Deleting server from favorites.
2016-10-04 23:39:32 +05:00
func ( m * MainWindow ) deleteFromFavorites () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Removing server from favorites..." )
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
server_address := m . getIpFromServersList ( current_tab )
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
var not_favorited bool = false
if len ( server_address ) > 0 {
if ctx . Cache . Servers [ server_address ]. Server . Favorite == "1" {
ctx . Cache . Servers [ server_address ]. Server . Favorite = "0"
} else {
not_favorited = true
}
} else {
not_favorited = true
}
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
if not_favorited {
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime . GOOS != "linux" {
mbox_string := ctx . Translator . Translate ( "Cannot delete server from favorites.\n\nServer isn't favorited." , nil )
d := gtk . NewMessageDialog ( m . window , gtk . DIALOG_MODAL , gtk . MESSAGE_INFO , gtk . BUTTONS_OK , mbox_string )
d . Response ( func () {
d . Destroy ()
})
d . Run ()
} else {
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx . Translator . Translate ( "Server isn't favorited" , nil ) + "</span></markup>" })
}
}
2016-10-07 14:28:44 +05:00
2018-11-10 13:21:53 +05:00
ctx . Eventer . LaunchEvent ( "loadFavoriteServers" , map [ string ] string {})
2016-10-04 23:39:32 +05:00
}
2016-10-06 13:55:03 +05:00
// Drop database data.
// ToDo: extend so we should have an ability to decide what to drop.
2016-10-04 23:39:32 +05:00
func ( m * MainWindow ) dropDatabasesData () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Dropping database data..." )
var will_continue bool = false
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime . GOOS != "linux" {
mbox_string := ctx . Translator . Translate ( "You are about to drop whole database data.\n\nAfter clicking \"YES\" ALL data in database (servers, profiles, settings, etc.)\nwill be lost FOREVER. Are you sure?" , nil )
d := gtk . NewMessageDialog ( m . window , gtk . DIALOG_MODAL , gtk . MESSAGE_WARNING , gtk . BUTTONS_YES_NO , mbox_string )
d . Connect ( "response" , func ( resp * glib . CallbackContext ) {
if resp . Args ( 0 ) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
d . Destroy ()
})
d . Run ()
} else {
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx . Translator . Translate ( "Remove ~/.config/urtrator/database.sqlite3 manually!" , nil ) + "</span></markup>" })
}
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
if will_continue {
ctx . Database . Db . MustExec ( "DELETE FROM servers" )
ctx . Database . Db . MustExec ( "DELETE FROM settings" )
ctx . Database . Db . MustExec ( "DELETE FROM urt_profiles" )
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
ctx . Eventer . LaunchEvent ( "loadProfiles" , map [ string ] string {})
ctx . Eventer . LaunchEvent ( "loadAllServers" , map [ string ] string {})
ctx . Eventer . LaunchEvent ( "loadFavoriteServers" , map [ string ] string {})
}
2016-10-04 23:39:32 +05:00
}
2016-10-06 13:55:03 +05:00
// Executes on "Edit favorite server" click.
2016-10-05 00:04:24 +05:00
func ( m * MainWindow ) editFavorite () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Editing favorite server..." )
2016-10-05 00:04:24 +05:00
2018-11-10 13:21:53 +05:00
server_address := m . getIpFromServersList ( "Favorites" )
2016-10-05 00:04:24 +05:00
2018-11-10 13:21:53 +05:00
if len ( server_address ) > 0 {
srv := ctx . Cache . Servers [ server_address ]. Server
fd := FavoriteDialog {}
fd . InitializeUpdate ( srv )
}
2016-10-05 00:04:24 +05:00
}
2016-11-26 16:20:57 +05:00
func ( m * MainWindow ) favServersGamemodeFilterChanged () {
2018-11-10 13:21:53 +05:00
ctx . Cfg . Cfg [ "/serverslist/favorite/gamemode" ] = strconv . Itoa ( m . fav_servers_gamemode . GetActive ())
ctx . Eventer . LaunchEvent ( "loadFavoriteServers" , nil )
2016-11-26 16:20:57 +05:00
}
2016-11-26 16:00:17 +05:00
func ( m * MainWindow ) favServersVersionFilterChanged () {
2018-11-10 13:21:53 +05:00
ctx . Cfg . Cfg [ "/serverslist/favorite/version" ] = strconv . Itoa ( m . fav_servers_version . GetActive ())
ctx . Eventer . LaunchEvent ( "loadFavoriteServers" , nil )
2016-11-26 16:00:17 +05:00
}
2016-10-06 13:55:03 +05:00
// Executes when "Hide offline servers" checkbox changed it's state on
// "Servers" tab.
2016-10-04 15:42:36 +05:00
func ( m * MainWindow ) hideOfflineAllServers () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "(Un)Hiding offline servers in 'Servers' tab..." )
if m . all_servers_hide_offline . GetActive () {
ctx . Cfg . Cfg [ "/serverslist/all_servers/hide_offline" ] = "1"
} else {
ctx . Cfg . Cfg [ "/serverslist/all_servers/hide_offline" ] = "0"
}
ctx . Eventer . LaunchEvent ( "loadAllServers" , map [ string ] string {})
2016-10-04 15:42:36 +05:00
}
2016-11-23 09:49:39 +05:00
// Executes when "Hide passworded servers" checkbox changed it's state on
// "Servers" tab.
func ( m * MainWindow ) hidePrivateAllServers () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "(Un)Hiding private servers in 'Servers' tab..." )
if m . all_servers_hide_private . GetActive () {
ctx . Cfg . Cfg [ "/serverslist/all_servers/hide_private" ] = "1"
} else {
ctx . Cfg . Cfg [ "/serverslist/all_servers/hide_private" ] = "0"
}
ctx . Eventer . LaunchEvent ( "loadAllServers" , map [ string ] string {})
2016-11-23 09:49:39 +05:00
}
2016-10-06 13:55:03 +05:00
// Executes when "Hide offline servers" checkbox changed it's state on
// "Favorites" tab.
2016-10-04 15:42:36 +05:00
func ( m * MainWindow ) hideOfflineFavoriteServers () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "(Un)Hiding offline servers in 'Favorite' tab..." )
if m . fav_servers_hide_offline . GetActive () {
ctx . Cfg . Cfg [ "/serverslist/favorite/hide_offline" ] = "1"
} else {
ctx . Cfg . Cfg [ "/serverslist/favorite/hide_offline" ] = "0"
}
ctx . Eventer . LaunchEvent ( "loadFavoriteServers" , map [ string ] string {})
2016-10-04 15:42:36 +05:00
}
2016-11-23 09:49:39 +05:00
// Executes when "Hide passworded servers" checkbox changed it's state on
// "Favorites" tab.
func ( m * MainWindow ) hidePrivateFavoriteServers () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "(Un)Hiding private servers in 'Favorite' tab..." )
if m . all_servers_hide_private . GetActive () {
ctx . Cfg . Cfg [ "/serverslist/favorite/hide_private" ] = "1"
} else {
ctx . Cfg . Cfg [ "/serverslist/favorite/hide_private" ] = "0"
}
ctx . Eventer . LaunchEvent ( "loadFavoriteServers" , map [ string ] string {})
2016-11-23 09:49:39 +05:00
}
2016-10-08 19:57:33 +05:00
func ( m * MainWindow ) loadAllServers ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Loading all servers..." )
for _ , server := range ctx . Cache . Servers {
iter := new ( gtk . TreeIter )
ping , _ := strconv . Atoi ( server . Server . Ping )
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
if ! server . AllServersIterSet {
server . AllServersIter = iter
server . AllServersIterSet = true
} else {
iter = server . AllServersIter
}
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
// Hide offline servers?
if m . all_servers_hide_offline . GetActive () && ( server . Server . Players == "" && server . Server . Maxplayers == "" || ping > 9000 ) {
if server . AllServersIterInList && server . AllServersIterSet {
m . all_servers_store . Remove ( iter )
server . AllServersIterInList = false
}
continue
}
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
// Hide private servers?
if m . all_servers_hide_private . GetActive () && server . Server . IsPrivate == "1" {
if server . AllServersIterInList && server . AllServersIterSet {
m . all_servers_store . Remove ( iter )
server . AllServersIterInList = false
}
continue
}
2016-11-23 09:49:39 +05:00
2018-11-10 13:21:53 +05:00
// Hide servers that using different version than selected in
// filter?
if m . all_servers_version . GetActiveText () != ctx . Translator . Translate ( "All versions" , nil ) && m . all_servers_version . GetActiveText () != server . Server . Version {
if server . AllServersIterInList && server . AllServersIterSet {
m . all_servers_store . Remove ( iter )
server . AllServersIterInList = false
}
continue
}
2016-11-26 16:20:57 +05:00
2018-11-10 13:21:53 +05:00
// Hide servers that using different gamemode than selected in
// filter?
gm_int_as_str := strconv . Itoa ( m . all_servers_gamemode . GetActive ())
if m . all_servers_gamemode . GetActiveText () != ctx . Translator . Translate ( "All gamemodes" , nil ) && gm_int_as_str != server . Server . Gamemode {
if server . AllServersIterInList && server . AllServersIterSet {
m . all_servers_store . Remove ( iter )
server . AllServersIterInList = false
}
continue
}
2016-11-26 16:00:17 +05:00
2018-11-10 13:21:53 +05:00
if ! server . AllServersIterInList && server . AllServersIterSet {
m . all_servers_store . Append ( iter )
server . AllServersIterInList = true
}
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
if server . Server . Name == "" && server . Server . Players == "" {
m . all_servers_store . SetValue ( iter , 0 , m . server_offline_pic . GPixbuf )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "IP" , nil )], server . Server . Ip + ":" + server . Server . Port )
} else {
if ping > 9000 {
m . all_servers_store . SetValue ( iter , 0 , m . server_offline_pic . GPixbuf )
} else {
m . all_servers_store . SetValue ( iter , 0 , m . server_online_pic . GPixbuf )
}
if server . Server . IsPrivate == "1" {
m . all_servers_store . SetValue ( iter , 1 , m . server_private_pic . GPixbuf )
} else {
m . all_servers_store . SetValue ( iter , 1 , m . server_public_pic . GPixbuf )
}
server_name := ctx . Colorizer . Fix ( server . Server . Name )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "Name" , nil )], server_name )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "Mode" , nil )], m . getGameModeName ( server . Server . Gamemode ))
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "Map" , nil )], server . Server . Map )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "Players" , nil )], server . Server . Players + "/" + server . Server . Bots + "/" + server . Server . Maxplayers )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "Ping" , nil )], server . Server . Ping )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "Version" , nil )], server . Server . Version )
m . all_servers_store . SetValue ( iter , m . column_pos [ "Servers" ][ ctx . Translator . Translate ( "IP" , nil )], server . Server . Ip + ":" + server . Server . Port )
}
}
2016-10-04 15:42:36 +05:00
}
2016-10-08 19:57:33 +05:00
func ( m * MainWindow ) loadFavoriteServers ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Loading favorite servers..." )
for _ , server := range ctx . Cache . Servers {
iter := new ( gtk . TreeIter )
ping , _ := strconv . Atoi ( server . Server . Ping )
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
if ! server . FavServersIterSet {
server . FavServersIter = iter
server . FavServersIterSet = true
} else {
iter = server . FavServersIter
}
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
// Hide offline servers?
if m . fav_servers_hide_offline . GetActive () && ( server . Server . Players == "" && server . Server . Maxplayers == "" || ping > 9000 ) {
if server . FavServersIterInList {
m . fav_servers_store . Remove ( iter )
server . FavServersIterInList = false
}
continue
}
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
// Hide private servers?
if m . fav_servers_hide_private . GetActive () && server . Server . IsPrivate == "1" {
if server . FavServersIterInList && server . FavServersIterSet {
m . fav_servers_store . Remove ( iter )
server . FavServersIterInList = false
}
continue
}
2016-11-23 09:49:39 +05:00
2018-11-10 13:21:53 +05:00
// Hide servers that using different version than selected in
// filter?
if m . fav_servers_version . GetActiveText () != ctx . Translator . Translate ( "All versions" , nil ) && m . fav_servers_version . GetActiveText () != server . Server . Version {
if server . FavServersIterInList && server . FavServersIterSet {
m . fav_servers_store . Remove ( iter )
server . FavServersIterInList = false
}
continue
}
2016-11-26 16:20:57 +05:00
2018-11-10 13:21:53 +05:00
// Hide servers that using different gamemode than selected in
// filter?
gm_int_as_str := strconv . Itoa ( m . fav_servers_gamemode . GetActive ())
if m . fav_servers_gamemode . GetActiveText () != ctx . Translator . Translate ( "All gamemodes" , nil ) && gm_int_as_str != server . Server . Gamemode {
if server . FavServersIterInList && server . FavServersIterSet {
m . fav_servers_store . Remove ( iter )
server . FavServersIterInList = false
}
continue
}
2016-11-26 16:00:17 +05:00
2018-11-10 13:21:53 +05:00
// If server on favorites widget, but not favorited (e.g. just
// removed from favorites) - remove it from list.
if server . Server . Favorite != "1" && server . FavServersIterSet && server . FavServersIterInList {
m . fav_servers_store . Remove ( server . FavServersIter )
server . FavServersIterInList = false
server . FavServersIterSet = false
}
2016-10-08 00:01:20 +05:00
2018-11-10 13:21:53 +05:00
// Server isn't in favorites and wasn't previously added to widget.
if server . Server . Favorite != "1" {
continue
}
2016-10-06 22:43:45 +05:00
2018-11-10 13:21:53 +05:00
if ! server . FavServersIterInList && server . FavServersIterSet {
m . fav_servers_store . Append ( iter )
server . FavServersIterInList = true
}
2016-10-08 00:01:20 +05:00
2018-11-10 13:21:53 +05:00
if server . Server . Name == "" && server . Server . Players == "" {
m . fav_servers_store . SetValue ( iter , 0 , m . server_offline_pic . GPixbuf )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "IP" , nil )], server . Server . Ip + ":" + server . Server . Port )
} else {
if ping > 9000 {
m . fav_servers_store . SetValue ( iter , 0 , m . server_offline_pic . GPixbuf )
} else {
m . fav_servers_store . SetValue ( iter , 0 , m . server_online_pic . GPixbuf )
}
if server . Server . IsPrivate == "1" {
m . fav_servers_store . SetValue ( iter , 1 , m . server_private_pic . GPixbuf )
} else {
m . fav_servers_store . SetValue ( iter , 1 , m . server_public_pic . GPixbuf )
}
server_name := ctx . Colorizer . Fix ( server . Server . Name )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "Name" , nil )], server_name )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "Mode" , nil )], m . getGameModeName ( server . Server . Gamemode ))
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "Map" , nil )], server . Server . Map )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "Players" , nil )], server . Server . Players + "/" + server . Server . Bots + "/" + server . Server . Maxplayers )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "Ping" , nil )], server . Server . Ping )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "Version" , nil )], server . Server . Version )
m . fav_servers_store . SetValue ( iter , m . column_pos [ "Favorites" ][ ctx . Translator . Translate ( "IP" , nil )], server . Server . Ip + ":" + server . Server . Port )
}
}
2016-10-04 23:39:32 +05:00
}
2016-10-08 19:57:33 +05:00
func ( m * MainWindow ) loadProfiles ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Loading profiles into combobox on MainWindow" )
for i := 0 ; i < m . old_profiles_count ; i ++ {
// ComboBox indexes are shifting on element deletion, so we should
// detele very first element every time.
m . profiles . Remove ( 0 )
}
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
for _ , profile := range ctx . Cache . Profiles {
m . profiles . AppendText ( profile . Profile . Name )
}
2016-10-04 23:39:32 +05:00
2018-11-10 13:21:53 +05:00
m . old_profiles_count = len ( ctx . Cache . Profiles )
fmt . Println ( "Added " + strconv . Itoa ( m . old_profiles_count ) + " profiles" )
2016-11-22 18:33:53 +05:00
2018-11-10 13:21:53 +05:00
m . profiles . SetActive ( 0 )
2016-10-04 23:39:32 +05:00
}
2016-11-25 03:12:05 +05:00
func ( m * MainWindow ) tabChanged () {
2018-11-10 13:21:53 +05:00
if ! m . initialized {
return
}
2016-11-25 03:12:05 +05:00
2018-11-10 13:21:53 +05:00
fmt . Println ( "Active tab changed..." )
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
fmt . Println ( current_tab )
2016-11-25 03:12:05 +05:00
2018-11-10 13:21:53 +05:00
m . use_other_servers_tab = true
if strings . Contains ( current_tab , ctx . Translator . Translate ( "Servers" , nil )) {
m . fav_servers . Emit ( "cursor-changed" )
} else if strings . Contains ( current_tab , ctx . Translator . Translate ( "Favorites" , nil )) {
m . all_servers . Emit ( "cursor-changed" )
}
m . use_other_servers_tab = false
2016-11-25 03:12:05 +05:00
}
2016-10-08 19:57:33 +05:00
func ( m * MainWindow ) serversUpdateCompleted ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : ctx . Translator . Translate ( "Servers updated." , nil )})
// Trigger "selection-changed" events on currently active tab's
// servers list.
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
2016-11-23 10:10:11 +05:00
2018-11-10 13:21:53 +05:00
if strings . Contains ( current_tab , ctx . Translator . Translate ( "Servers" , nil )) {
m . all_servers . Emit ( "cursor-changed" )
} else if strings . Contains ( current_tab , ctx . Translator . Translate ( "Favorites" , nil )) {
m . fav_servers . Emit ( "cursor-changed" )
}
2016-11-23 10:10:11 +05:00
2018-11-10 13:21:53 +05:00
m . servers_already_updating = false
2017-05-08 23:38:54 +05:00
2016-10-08 19:57:33 +05:00
}
2016-10-11 13:14:08 +05:00
func ( m * MainWindow ) setQuickConnectDetails ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Setting quick connect data..." )
m . qc_server_address . SetText ( data [ "server" ])
m . qc_password . SetText ( data [ "password" ])
2016-10-11 13:14:08 +05:00
}
2016-10-08 19:57:33 +05:00
func ( m * MainWindow ) setToolbarLabelText ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Setting toolbar's label text..." )
if strings . Contains ( data [ "text" ], "<markup>" ) {
fmt . Println ( "With markup" )
m . toolbar_label . SetMarkup ( data [ "text" ])
} else {
fmt . Println ( "Without markup" )
m . toolbar_label . SetLabel ( data [ "text" ])
}
2016-10-06 13:55:03 +05:00
}
2016-10-05 01:03:46 +05:00
func ( m * MainWindow ) showHide () {
2018-11-10 13:21:53 +05:00
if m . hidden {
m . window . Show ()
m . hidden = false
// Set window position on restore. Window loosing it on
// multimonitor configurations.
m . window . Move ( m . window_pos_x , m . window_pos_y )
} else {
m . window . Hide ()
m . hidden = true
}
2016-10-05 01:03:46 +05:00
}
2016-11-26 09:05:48 +05:00
func ( m * MainWindow ) showServerCVars () {
2018-11-10 13:21:53 +05:00
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
if m . use_other_servers_tab {
if strings . Contains ( current_tab , ctx . Translator . Translate ( "Servers" , nil )) {
current_tab = "Favorites"
} else if strings . Contains ( current_tab , ctx . Translator . Translate ( "Favorites" , nil )) {
current_tab = "Servers"
}
}
srv_address := m . getIpFromServersList ( current_tab )
if len ( srv_address ) > 0 {
m . server_cvars_dialog . Initialize ( m . window , srv_address )
}
2016-11-26 09:05:48 +05:00
}
2016-10-06 20:48:35 +05:00
func ( m * MainWindow ) showShortServerInformation () {
2018-11-10 13:21:53 +05:00
fmt . Println ( "Server selection changed, updating server's information widget..." )
m . server_info_store . Clear ()
m . players_info_store . Clear ()
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
if m . use_other_servers_tab {
if strings . Contains ( current_tab , ctx . Translator . Translate ( "Servers" , nil )) {
current_tab = "Favorites"
} else if strings . Contains ( current_tab , ctx . Translator . Translate ( "Favorites" , nil )) {
current_tab = "Servers"
}
}
srv_address := m . getIpFromServersList ( current_tab )
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Getting server information from cache.
if len ( srv_address ) > 0 && ctx . Cache . Servers [ srv_address ]. Server . Players != "" {
server_info := ctx . Cache . Servers [ srv_address ]. Server
parsed_general_data := ioq3dataparser . ParseInfoToMap ( server_info . ExtendedConfig )
parsed_players_info := ioq3dataparser . ParsePlayersInfoToMap ( server_info . PlayersInfo )
// Append to treeview generic info first. After appending it
// will be deleted from map.
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Server's name.
iter := new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Server's name" , nil ))
m . server_info_store . SetValue ( iter , 1 , ctx . Colorizer . Fix ( parsed_general_data [ "sv_hostname" ]))
delete ( parsed_general_data , "sv_hostname" )
2016-10-06 21:34:14 +05:00
2018-11-10 13:21:53 +05:00
// Game version.
iter = new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Game version" , nil ))
m . server_info_store . SetValue ( iter , 1 , parsed_general_data [ "g_modversion" ])
delete ( parsed_general_data , "g_modversion" )
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Players.
iter = new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Players" , nil ))
m . server_info_store . SetValue ( iter , 1 , server_info . Players + " of " + parsed_general_data [ "sv_maxclients" ] + " (" + server_info . Bots + " bots)" )
delete ( parsed_general_data , "sv_maxclients" )
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Ping
iter = new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Ping" , nil ))
m . server_info_store . SetValue ( iter , 1 , server_info . Ping + " ms" )
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Game mode
iter = new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Game mode" , nil ))
m . server_info_store . SetValue ( iter , 1 , m . gamemodes [ server_info . Gamemode ])
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Map name
iter = new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Current map" , nil ))
m . server_info_store . SetValue ( iter , 1 , server_info . Map )
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Private or public?
iter = new ( gtk . TreeIter )
m . server_info_store . Append ( iter )
m . server_info_store . SetValue ( iter , 0 , ctx . Translator . Translate ( "Passworded" , nil ))
passworded_status := "<markup><span foreground=\"green\">" + ctx . Translator . Translate ( "No" , nil ) + "</span></markup>"
if server_info . IsPrivate == "1" {
passworded_status = "<markup><span foreground=\"red\">" + ctx . Translator . Translate ( "Yes" , nil ) + "</span></markup>"
}
m . server_info_store . SetValue ( iter , 1 , passworded_status )
2016-10-06 21:34:14 +05:00
2018-11-10 13:21:53 +05:00
// Sorting keys of map.
players_map_keys := make ([] string , 0 , len ( parsed_players_info ))
for k := range parsed_players_info {
// ToDo: figure out how to do this properly without
// append().
players_map_keys = append ( players_map_keys , k )
}
2016-11-23 07:51:41 +05:00
2018-11-10 13:21:53 +05:00
sort . Strings ( players_map_keys )
2016-11-23 07:51:41 +05:00
2018-11-10 13:21:53 +05:00
for k := range players_map_keys {
iter = new ( gtk . TreeIter )
nick := ctx . Colorizer . Fix ( parsed_players_info [ players_map_keys [ k ]][ "nick" ])
m . players_info_store . Append ( iter )
m . players_info_store . SetValue ( iter , 0 , nick )
m . players_info_store . SetValue ( iter , 1 , parsed_players_info [ players_map_keys [ k ]][ "frags" ])
m . players_info_store . SetValue ( iter , 2 , parsed_players_info [ players_map_keys [ k ]][ "ping" ])
}
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
/*
// Just a separator.
iter = new(gtk.TreeIter)
m.server_info_store.Append(iter)
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Other parameters :).
iter = new(gtk.TreeIter)
m.server_info_store.Append(iter)
m.server_info_store.SetValue(iter, 0, "<markup><span font_weight=\"bold\">OTHER PARAMETERS</span></markup>")
2016-10-06 20:48:35 +05:00
2018-11-10 13:21:53 +05:00
// Sort it!
general_data_keys := make([]string, 0, len(parsed_general_data))
for k := range parsed_general_data {
general_data_keys = append(general_data_keys, k)
}
2016-11-23 07:51:41 +05:00
2018-11-10 13:21:53 +05:00
sort.Strings(general_data_keys)
2016-11-23 07:51:41 +05:00
2018-11-10 13:21:53 +05:00
for k := range general_data_keys {
iter = new(gtk.TreeIter)
m.server_info_store.Append(iter)
m.server_info_store.SetValue(iter, 0, general_data_keys[k])
m.server_info_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]])
}
*/
}
2016-10-06 20:48:35 +05:00
}
2016-10-06 17:11:36 +05:00
// Show tray menu on right-click on tray icon.
2016-10-05 01:03:46 +05:00
func ( m * MainWindow ) showTrayMenu ( cbx * glib . CallbackContext ) {
2018-11-10 13:21:53 +05:00
m . tray_menu . Popup ( nil , nil , gtk . StatusIconPositionMenu , m . tray_icon , uint ( cbx . Args ( 0 )), uint32 ( cbx . Args ( 1 )))
2016-10-05 01:03:46 +05:00
}
2016-10-06 17:11:36 +05:00
// Unlocking interface after game shut down.
2016-10-04 15:42:36 +05:00
func ( m * MainWindow ) unlockInterface () {
2018-11-10 13:21:53 +05:00
m . launch_button . SetSensitive ( true )
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : ctx . Translator . Translate ( "URTrator is ready." , nil )})
2016-10-04 15:42:36 +05:00
}
2016-10-07 14:28:44 +05:00
func ( m * MainWindow ) updateOneServer () {
2018-11-10 13:21:53 +05:00
if m . servers_already_updating {
return
}
m . servers_already_updating = true
2017-05-08 23:38:54 +05:00
2018-11-10 13:21:53 +05:00
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx . Translator . Translate ( "Updating selected server..." , nil ) + "</span></markup>" })
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
srv_address := m . getIpFromServersList ( current_tab )
2016-10-07 14:28:44 +05:00
2018-11-10 13:21:53 +05:00
if len ( srv_address ) > 0 {
go ctx . Requester . UpdateOneServer ( srv_address )
}
2016-10-07 14:28:44 +05:00
}
2016-10-06 13:55:03 +05:00
// Triggered when "Update all servers" button is clicked.
2016-10-04 15:42:36 +05:00
func ( m * MainWindow ) UpdateServers () {
2018-11-10 13:21:53 +05:00
if m . servers_already_updating {
return
}
m . servers_already_updating = true
2017-05-08 23:38:54 +05:00
2018-11-10 13:21:53 +05:00
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx . Translator . Translate ( "Updating servers..." , nil ) + "</span></markup>" })
current_tab := m . tab_widget . GetTabLabelText ( m . tab_widget . GetNthPage ( m . tab_widget . GetCurrentPage ()))
fmt . Println ( "Updating servers on tab '" + current_tab + "'..." )
2016-10-06 13:55:03 +05:00
2018-11-10 13:21:53 +05:00
if strings . Contains ( current_tab , ctx . Translator . Translate ( "Servers" , nil )) {
go ctx . Requester . UpdateAllServers ( false )
} else if strings . Contains ( current_tab , ctx . Translator . Translate ( "Favorites" , nil )) {
go ctx . Requester . UpdateFavoriteServers ()
}
2016-10-04 15:42:36 +05:00
}
2016-12-13 08:01:48 +05:00
func ( m * MainWindow ) UpdateServersEventHandler ( data map [ string ] string ) {
2018-11-10 13:21:53 +05:00
ctx . Eventer . LaunchEvent ( "setToolbarLabelText" , map [ string ] string { "text" : "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx . Translator . Translate ( "Updating servers..." , nil ) + "</span></markup>" })
2016-12-13 08:01:48 +05:00
2018-11-10 13:21:53 +05:00
go ctx . Requester . UpdateAllServers ( true )
2016-12-13 08:01:48 +05:00
}