2016-10-04 15:42:36 +05:00
// URTator - Urban Terror server browser and game launcher, written in
// Go.
//
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
// All rights reserved.
//
// Licensed under Terms and Conditions of GNU General Public License
// version 3 or any higher.
// ToDo: put full text of license here.
package ui
import (
// stdlib
"fmt"
"os"
2016-10-09 13:27:16 +05:00
"runtime"
2016-10-04 15:42:36 +05:00
"strings"
// Local
"github.com/pztrn/urtrator/datamodels"
// Other
"github.com/mattn/go-gtk/gtk"
//"github.com/mattn/go-gtk/glib"
)
type OptionsProfile struct {
// Window.
window * gtk . Window
2016-11-25 04:11:44 +05:00
// Main table.
table * gtk . Table
2016-10-04 15:42:36 +05:00
// Profile name.
profile_name * gtk . Entry
// Binary path.
binary_path * gtk . Entry
// Urban Terror versions combobox
urt_version_combo * gtk . ComboBoxText
// Another X session?
another_x_session * gtk . CheckButton
// Additional parameters for game launching.
additional_parameters * gtk . Entry
// File chooser dialog for selecting binary.
f * gtk . FileChooserDialog
// Flags.
// This is profile update?
update bool
// Others.
// Old profile, needed for proper update.
old_profile * datamodels . Profile
}
func ( op * OptionsProfile ) browseForBinary ( ) {
2016-10-09 17:06:47 +05:00
op . f = gtk . NewFileChooserDialog ( "URTrator - Select Urban Terror binary" , op . window , gtk . FILE_CHOOSER_ACTION_OPEN , gtk . STOCK_OK , gtk . RESPONSE_ACCEPT )
2016-10-04 15:42:36 +05:00
op . f . Response ( op . browseForBinaryHelper )
op . f . Run ( )
}
func ( op * OptionsProfile ) browseForBinaryHelper ( ) {
filename := op . f . GetFilename ( )
op . binary_path . SetText ( filename )
op . f . Destroy ( )
2016-10-09 17:06:47 +05:00
fmt . Println ( filename )
2016-10-04 15:42:36 +05:00
// Check for valid filename.
// ToDo: add more OSes.
if runtime . GOOS == "linux" {
// Filename should end with approriate arch.
if runtime . GOARCH == "amd64" {
if len ( filename ) > 0 && strings . Split ( filename , "." ) [ 1 ] != "x86_64" && strings . Split ( filename , "." ) [ 0 ] != "Quake3-UrT" {
fmt . Println ( "Invalid binary selected!" )
2016-11-22 01:10:31 +05:00
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime . GOOS != "linux" {
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.x86_64."
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
} else {
//
}
2016-10-04 15:42:36 +05:00
op . binary_path . SetText ( "" )
}
}
2016-10-04 18:47:47 +05:00
} else if runtime . GOOS == "darwin" {
2016-10-09 17:06:47 +05:00
// Official application: Quake3-UrT.app. Split by it and get second
// part of string.
if strings . Contains ( filename , "Quake3-UrT.app" ) {
filename = strings . Split ( filename , "Quake3-UrT.app" ) [ 1 ]
if len ( filename ) > 0 && ! strings . Contains ( strings . Split ( filename , "." ) [ 1 ] , "x86_64" ) && ! strings . Contains ( strings . Split ( filename , "." ) [ 0 ] , "Quake3-UrT" ) {
fmt . Println ( "Invalid binary selected!" )
2016-11-22 01:10:31 +05:00
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime . GOOS != "linux" {
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64."
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
} else {
//
}
op . binary_path . SetText ( "" )
}
} else {
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime . GOOS != "linux" {
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64.\n\nNote, that currently URTrator supports only official binary."
2016-10-09 17:06:47 +05:00
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
2016-11-22 01:10:31 +05:00
} else {
//
2016-10-09 17:06:47 +05:00
}
2016-10-04 18:47:47 +05:00
}
2016-10-04 15:42:36 +05:00
}
}
func ( op * OptionsProfile ) closeByCancel ( ) {
op . window . Destroy ( )
}
func ( op * OptionsProfile ) closeWithDiscard ( ) {
}
2016-10-08 19:57:33 +05:00
func ( op * OptionsProfile ) Initialize ( update bool ) {
2016-10-04 15:42:36 +05:00
if update {
op . update = true
}
op . window = gtk . NewWindow ( gtk . WINDOW_TOPLEVEL )
if update {
op . window . SetTitle ( "URTrator - Update Urban Terror profile" )
} else {
op . window . SetTitle ( "URTrator - Add Urban Terror profile" )
}
op . window . Connect ( "destroy" , op . closeWithDiscard )
op . window . SetModal ( true )
op . window . SetSizeRequest ( 550 , 400 )
op . window . SetPosition ( gtk . WIN_POS_CENTER )
op . window . SetIcon ( logo )
2016-11-25 04:11:44 +05:00
op . table = gtk . NewTable ( 6 , 2 , false )
op . table . SetRowSpacings ( 2 )
2016-10-04 15:42:36 +05:00
// Profile name.
2016-10-04 19:21:48 +05:00
profile_name_tooltip := "This how you will see profile on profiles lists."
2016-10-04 15:42:36 +05:00
pn_label := gtk . NewLabel ( "Profile name:" )
2016-10-04 19:21:48 +05:00
pn_label . SetTooltipText ( profile_name_tooltip )
2016-11-25 04:11:44 +05:00
pn_label . SetAlignment ( 0 , 0 )
op . table . Attach ( pn_label , 0 , 1 , 0 , 1 , gtk . FILL , gtk . SHRINK , 5 , 5 )
2016-10-04 15:42:36 +05:00
op . profile_name = gtk . NewEntry ( )
2016-10-04 19:21:48 +05:00
op . profile_name . SetTooltipText ( profile_name_tooltip )
2016-11-25 04:11:44 +05:00
op . table . Attach ( op . profile_name , 1 , 2 , 0 , 1 , gtk . FILL , gtk . FILL , 5 , 5 )
2016-10-04 15:42:36 +05:00
// Urban Terror version.
2016-10-04 19:21:48 +05:00
urt_version_tooltip := "Urban Terror version for which this profile applies."
2016-10-04 15:42:36 +05:00
urt_version_label := gtk . NewLabel ( "Urban Terror version:" )
2016-10-04 19:21:48 +05:00
urt_version_label . SetTooltipText ( urt_version_tooltip )
2016-11-25 04:11:44 +05:00
urt_version_label . SetAlignment ( 0 , 0 )
op . table . Attach ( urt_version_label , 0 , 1 , 1 , 2 , gtk . FILL , gtk . SHRINK , 5 , 5 )
2016-10-04 15:42:36 +05:00
op . urt_version_combo = gtk . NewComboBoxText ( )
2016-10-04 19:21:48 +05:00
op . urt_version_combo . SetTooltipText ( urt_version_tooltip )
2016-10-04 15:42:36 +05:00
op . urt_version_combo . AppendText ( "4.2.023" )
2016-10-04 18:32:50 +05:00
op . urt_version_combo . AppendText ( "4.3.0" )
2016-10-06 15:44:24 +05:00
op . urt_version_combo . AppendText ( "4.3.1" )
2016-11-22 11:38:48 +05:00
op . urt_version_combo . SetActive ( 2 )
2016-11-25 04:11:44 +05:00
op . table . Attach ( op . urt_version_combo , 1 , 2 , 1 , 2 , gtk . FILL , gtk . FILL , 5 , 5 )
2016-10-04 15:42:36 +05:00
// Urban Terror binary path.
2016-10-04 19:21:48 +05:00
select_binary_tooltip := "Urban Terror binary. Some checks will be executed, so make sure you have selected right binary:\n\nQuake3-UrT.i386 for linux-x86\nQuake3-UrT.x86_64 for linux-amd64\nQuake3-UrT.app for macOS"
2016-10-04 15:42:36 +05:00
binpath_hbox := gtk . NewHBox ( false , 0 )
binpath_label := gtk . NewLabel ( "Urban Terror binary:" )
2016-10-04 19:21:48 +05:00
binpath_label . SetTooltipText ( select_binary_tooltip )
2016-11-25 04:11:44 +05:00
binpath_label . SetAlignment ( 0 , 0 )
op . table . Attach ( binpath_label , 0 , 1 , 2 , 3 , gtk . FILL , gtk . SHRINK , 5 , 5 )
2016-10-04 15:42:36 +05:00
op . binary_path = gtk . NewEntry ( )
2016-10-04 19:21:48 +05:00
op . binary_path . SetTooltipText ( select_binary_tooltip )
2016-10-04 15:42:36 +05:00
button_select_binary := gtk . NewButtonWithLabel ( "Browse" )
2016-10-04 19:21:48 +05:00
button_select_binary . SetTooltipText ( select_binary_tooltip )
2016-10-04 15:42:36 +05:00
button_select_binary . Clicked ( op . browseForBinary )
binpath_hbox . PackStart ( op . binary_path , true , true , 5 )
binpath_hbox . PackStart ( button_select_binary , false , true , 5 )
2016-11-25 04:11:44 +05:00
op . table . Attach ( binpath_hbox , 1 , 2 , 2 , 3 , gtk . FILL , gtk . FILL , 0 , 0 )
2016-10-04 15:42:36 +05:00
// Should we use additional X session?
2016-10-04 19:21:48 +05:00
another_x_tooltip := "If this is checked, Urban Terror will be launched in another X session.\n\nThis could help if you're experiencing visual lag, glitches and FPS drops under compositing WMs, like Mutter and KWin."
2016-11-25 04:11:44 +05:00
another_x_label := gtk . NewLabel ( "Start Urban Terror in another X session?" )
another_x_label . SetTooltipText ( another_x_tooltip )
another_x_label . SetAlignment ( 0 , 0 )
op . table . Attach ( another_x_label , 0 , 1 , 3 , 4 , gtk . FILL , gtk . SHRINK , 5 , 5 )
op . another_x_session = gtk . NewCheckButtonWithLabel ( "" )
2016-10-04 19:21:48 +05:00
op . another_x_session . SetTooltipText ( another_x_tooltip )
2016-11-25 04:11:44 +05:00
// macOS and Windows can't do that :).
2016-10-09 17:06:47 +05:00
if runtime . GOOS != "linux" {
2016-10-04 18:47:47 +05:00
op . another_x_session . SetSensitive ( false )
}
2016-11-25 04:11:44 +05:00
op . table . Attach ( op . another_x_session , 1 , 2 , 3 , 4 , gtk . FILL , gtk . FILL , 5 , 5 )
2016-10-04 15:42:36 +05:00
// Additional game parameters.
2016-10-04 19:21:48 +05:00
params_tooltip := "Additional parameters that will be passed to Urban Terror executable."
2016-10-04 15:42:36 +05:00
params_label := gtk . NewLabel ( "Additional parameters:" )
2016-10-04 19:21:48 +05:00
params_label . SetTooltipText ( params_tooltip )
2016-11-25 04:11:44 +05:00
params_label . SetAlignment ( 0 , 0 )
op . table . Attach ( params_label , 0 , 1 , 4 , 5 , gtk . FILL , gtk . SHRINK , 5 , 5 )
2016-10-04 15:42:36 +05:00
op . additional_parameters = gtk . NewEntry ( )
2016-10-04 19:21:48 +05:00
op . additional_parameters . SetTooltipText ( params_tooltip )
2016-11-25 04:11:44 +05:00
op . table . Attach ( op . additional_parameters , 1 , 2 , 4 , 5 , gtk . FILL , gtk . FILL , 5 , 5 )
2016-10-04 15:42:36 +05:00
2016-11-25 04:11:44 +05:00
// Invisible thing.
inv_label := gtk . NewLabel ( "" )
op . table . Attach ( inv_label , 1 , 2 , 5 , 6 , gtk . EXPAND , gtk . FILL , 5 , 5 )
2016-10-04 15:42:36 +05:00
// The buttons.
buttons_box := gtk . NewHBox ( false , 0 )
2016-11-25 04:11:44 +05:00
buttons_sep := gtk . NewHBox ( false , 0 )
2016-10-04 15:42:36 +05:00
cancel_button := gtk . NewButtonWithLabel ( "Cancel" )
2016-10-04 19:21:48 +05:00
cancel_button . SetTooltipText ( "Close without saving" )
2016-10-04 15:42:36 +05:00
cancel_button . Clicked ( op . closeByCancel )
buttons_box . PackStart ( cancel_button , false , true , 5 )
buttons_box . PackStart ( buttons_sep , true , true , 5 )
add_button := gtk . NewButton ( )
if op . update {
add_button . SetLabel ( "Update" )
2016-10-04 19:21:48 +05:00
add_button . SetTooltipText ( "Update profile" )
2016-10-04 15:42:36 +05:00
} else {
add_button . SetLabel ( "Add" )
2016-10-04 19:21:48 +05:00
add_button . SetTooltipText ( "Add profile" )
2016-10-04 15:42:36 +05:00
}
add_button . Clicked ( op . saveProfile )
buttons_box . PackStart ( add_button , false , true , 5 )
2016-11-25 04:11:44 +05:00
vert_sep_box := gtk . NewVBox ( false , 0 )
vbox := gtk . NewVBox ( false , 0 )
vbox . PackStart ( op . table , false , true , 5 )
vbox . PackStart ( vert_sep_box , true , true , 5 )
vbox . PackStart ( buttons_box , false , true , 5 )
2016-10-04 15:42:36 +05:00
2016-11-25 04:11:44 +05:00
op . window . Add ( vbox )
2016-10-04 15:42:36 +05:00
op . window . ShowAll ( )
}
2016-10-08 19:57:33 +05:00
func ( op * OptionsProfile ) InitializeUpdate ( profile_name string ) {
2016-10-04 15:42:36 +05:00
fmt . Println ( "Updating profile '" + profile_name + "'" )
2016-10-08 19:57:33 +05:00
op . Initialize ( true )
2016-10-04 15:42:36 +05:00
// Get profile data.
2016-11-25 04:44:46 +05:00
profile := ctx . Cache . Profiles [ profile_name ] . Profile
op . profile_name . SetText ( profile . Name )
op . binary_path . SetText ( profile . Binary )
op . additional_parameters . SetText ( profile . Additional_params )
if profile . Second_x_session == "1" {
2016-10-04 15:42:36 +05:00
op . another_x_session . SetActive ( true )
}
2016-11-25 04:44:46 +05:00
if profile . Version == "4.3.0" {
2016-10-04 15:42:36 +05:00
op . urt_version_combo . SetActive ( 1 )
2016-11-25 04:49:19 +05:00
} else if profile . Version == "4.3.1" {
op . urt_version_combo . SetActive ( 2 )
2016-10-04 15:42:36 +05:00
} else {
op . urt_version_combo . SetActive ( 0 )
}
2016-11-25 04:44:46 +05:00
op . old_profile = profile
2016-10-04 15:42:36 +05:00
}
func ( op * OptionsProfile ) saveProfile ( ) {
fmt . Println ( "Saving profile..." )
// Validating fields.
// Profile name must not be empty.
if len ( op . profile_name . GetText ( ) ) < 1 {
mbox_string := "Empty profile name!\nProfile must be named somehow."
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
}
// Binary path must also be filled.
if len ( op . binary_path . GetText ( ) ) < 1 {
mbox_string := "Empty path to binary!\nThis profile will be unusable if you\nwill not provide path to binary!"
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
}
// ...and must be executable! :)
2016-10-08 19:57:33 +05:00
_ , err := os . Stat ( op . binary_path . GetText ( ) )
2016-10-04 15:42:36 +05:00
if err != nil {
mbox_string := "Invalid path to binary!\n\nError was:\n" + err . Error ( ) + "\n\nCheck binary path and try again."
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
} else {
// ToDo: executable flag checking.
2016-10-08 19:57:33 +05:00
//fmt.Println(filestat.Mode())
profile_name := op . profile_name . GetText ( )
2016-10-04 15:42:36 +05:00
2016-10-08 19:57:33 +05:00
_ , ok := ctx . Cache . Profiles [ profile_name ]
if ok && ! op . update {
2016-10-04 15:42:36 +05:00
mbox_string := "Game profile with same name already exist.\nRename profile for saving."
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
} else {
2016-10-08 19:57:33 +05:00
ctx . Cache . CreateProfile ( profile_name )
ctx . Cache . Profiles [ profile_name ] . Profile . Name = profile_name
ctx . Cache . Profiles [ profile_name ] . Profile . Version = op . urt_version_combo . GetActiveText ( )
ctx . Cache . Profiles [ profile_name ] . Profile . Binary = op . binary_path . GetText ( )
ctx . Cache . Profiles [ profile_name ] . Profile . Additional_params = op . additional_parameters . GetText ( )
if op . another_x_session . GetActive ( ) {
ctx . Cache . Profiles [ profile_name ] . Profile . Second_x_session = "1"
2016-10-04 15:42:36 +05:00
} else {
2016-10-08 19:57:33 +05:00
ctx . Cache . Profiles [ profile_name ] . Profile . Second_x_session = "0"
2016-10-04 15:42:36 +05:00
}
}
}
2016-10-08 19:57:33 +05:00
ctx . Eventer . LaunchEvent ( "loadProfilesIntoOptionsWindow" , map [ string ] string { } )
ctx . Eventer . LaunchEvent ( "loadProfilesIntoMainWindow" , map [ string ] string { } )
2016-10-04 15:42:36 +05:00
op . window . Destroy ( )
}