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"
"runtime"
"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
// Main Vertical Box.
vbox * gtk . VBox
// 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
// Callbacks.
// This will be triggered after we change profile.
loadProfiles func ( )
// Others.
// Old profile, needed for proper update.
old_profile * datamodels . Profile
}
func ( op * OptionsProfile ) browseForBinary ( ) {
op . f = gtk . NewFileChooserDialog ( "URTrator - Select Urban Terro binary" , op . window , gtk . FILE_CHOOSER_ACTION_OPEN , gtk . STOCK_OK , gtk . RESPONSE_ACCEPT )
op . f . Response ( op . browseForBinaryHelper )
op . f . Run ( )
}
func ( op * OptionsProfile ) browseForBinaryHelper ( ) {
filename := op . f . GetFilename ( )
op . binary_path . SetText ( filename )
op . f . Destroy ( )
// 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!" )
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 ( )
op . binary_path . SetText ( "" )
}
}
2016-10-04 18:47:47 +05:00
} else if runtime . GOOS == "darwin" {
// No separate arch thing here, macOS now 64bit only.
if len ( filename ) > 0 && strings . Split ( filename , "." ) [ 1 ] != "app" && strings . Split ( filename , "." ) [ 0 ] != "Quake3-UrT" {
fmt . Println ( "Invalid binary selected!" )
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app."
m := gtk . NewMessageDialog ( op . window , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , mbox_string )
m . Response ( func ( ) {
m . Destroy ( )
} )
m . Run ( )
op . binary_path . SetText ( "" )
}
2016-10-04 15:42:36 +05:00
}
}
func ( op * OptionsProfile ) closeByCancel ( ) {
op . window . Destroy ( )
}
func ( op * OptionsProfile ) closeWithDiscard ( ) {
}
func ( op * OptionsProfile ) Initialize ( update bool , lp func ( ) ) {
if update {
op . update = true
}
op . loadProfiles = lp
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 )
op . vbox = gtk . NewVBox ( false , 0 )
// Profile name.
pn_hbox := gtk . NewHBox ( false , 0 )
pn_label := gtk . NewLabel ( "Profile name:" )
sep1 := gtk . NewHSeparator ( )
op . profile_name = gtk . NewEntry ( )
pn_hbox . PackStart ( pn_label , false , true , 5 )
pn_hbox . PackStart ( sep1 , true , true , 5 )
pn_hbox . PackStart ( op . profile_name , true , true , 5 )
op . vbox . PackStart ( pn_hbox , false , true , 5 )
// Urban Terror version.
urt_version_hbox := gtk . NewHBox ( false , 0 )
urt_version_label := gtk . NewLabel ( "Urban Terror version:" )
urt_version_sep := gtk . NewHSeparator ( )
op . urt_version_combo = gtk . NewComboBoxText ( )
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-04 15:42:36 +05:00
op . urt_version_combo . SetActive ( 1 )
urt_version_hbox . PackStart ( urt_version_label , false , true , 5 )
urt_version_hbox . PackStart ( urt_version_sep , true , true , 5 )
urt_version_hbox . PackStart ( op . urt_version_combo , true , true , 5 )
op . vbox . PackStart ( urt_version_hbox , false , true , 5 )
// Urban Terror binary path.
binpath_hbox := gtk . NewHBox ( false , 0 )
binpath_label := gtk . NewLabel ( "Urban Terror binary:" )
sep2 := gtk . NewHSeparator ( )
op . binary_path = gtk . NewEntry ( )
button_select_binary := gtk . NewButtonWithLabel ( "Browse" )
button_select_binary . Clicked ( op . browseForBinary )
binpath_hbox . PackStart ( binpath_label , false , true , 5 )
binpath_hbox . PackStart ( sep2 , true , true , 5 )
binpath_hbox . PackStart ( op . binary_path , true , true , 5 )
binpath_hbox . PackStart ( button_select_binary , false , true , 5 )
op . vbox . PackStart ( binpath_hbox , false , true , 5 )
// Should we use additional X session?
op . another_x_session = gtk . NewCheckButtonWithLabel ( "Start Urban Terror in another X session?" )
op . vbox . PackStart ( op . another_x_session , false , true , 5 )
2016-10-04 18:47:47 +05:00
// macOS can't do that :).
if runtime . GOOS == "darwin" {
op . another_x_session . SetSensitive ( false )
}
2016-10-04 15:42:36 +05:00
// Additional game parameters.
params_hbox := gtk . NewHBox ( false , 0 )
params_label := gtk . NewLabel ( "Additional parameters:" )
params_sep := gtk . NewHSeparator ( )
op . additional_parameters = gtk . NewEntry ( )
params_hbox . PackStart ( params_label , false , true , 5 )
params_hbox . PackStart ( params_sep , true , true , 5 )
params_hbox . PackStart ( op . additional_parameters , true , true , 5 )
op . vbox . PackStart ( params_hbox , false , true , 5 )
// Vertical separator.
vert_sep := gtk . NewVSeparator ( )
op . vbox . PackStart ( vert_sep , true , true , 5 )
// The buttons.
buttons_box := gtk . NewHBox ( false , 0 )
buttons_sep := gtk . NewHSeparator ( )
cancel_button := gtk . NewButtonWithLabel ( "Cancel" )
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" )
} else {
add_button . SetLabel ( "Add" )
}
add_button . Clicked ( op . saveProfile )
buttons_box . PackStart ( add_button , false , true , 5 )
op . vbox . PackStart ( buttons_box , false , true , 5 )
op . window . Add ( op . vbox )
op . window . ShowAll ( )
}
func ( op * OptionsProfile ) InitializeUpdate ( profile_name string , lp func ( ) ) {
fmt . Println ( "Updating profile '" + profile_name + "'" )
op . Initialize ( true , lp )
// Get profile data.
profile := [ ] datamodels . Profile { }
err := ctx . Database . Db . Select ( & profile , ctx . Database . Db . Rebind ( "SELECT * FROM urt_profiles WHERE name=?" ) , profile_name )
if err != nil {
fmt . Println ( err . Error ( ) )
}
op . profile_name . SetText ( profile [ 0 ] . Name )
op . binary_path . SetText ( profile [ 0 ] . Binary )
op . additional_parameters . SetText ( profile [ 0 ] . Additional_params )
if profile [ 0 ] . Second_x_session == "1" {
op . another_x_session . SetActive ( true )
}
2016-10-04 18:32:50 +05:00
if profile [ 0 ] . Version == "4.3.0" {
2016-10-04 15:42:36 +05:00
op . urt_version_combo . SetActive ( 1 )
} else {
op . urt_version_combo . SetActive ( 0 )
}
op . old_profile = & profile [ 0 ]
}
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! :)
filestat , err := os . Stat ( op . binary_path . GetText ( ) )
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.
fmt . Println ( filestat . Mode ( ) )
// If we here - we can try to save game profile :).
profile := datamodels . Profile {
Name : op . profile_name . GetText ( ) ,
Version : op . urt_version_combo . GetActiveText ( ) ,
Binary : op . binary_path . GetText ( ) ,
Additional_params : op . additional_parameters . GetText ( ) ,
}
if op . another_x_session . GetActive ( ) {
profile . Second_x_session = "1"
} else {
profile . Second_x_session = "0"
}
// Check if we already have profile with such name.
profiles := [ ] datamodels . Profile { }
err1 := ctx . Database . Db . Select ( & profiles , "SELECT * FROM urt_profiles" )
if err1 != nil {
fmt . Println ( err1 . Error ( ) )
}
var found bool = false
for p := range profiles {
if profiles [ p ] . Name == profile . Name {
found = true
}
}
if found {
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 {
if op . update {
ctx . Database . Db . NamedExec ( "UPDATE urt_profiles SET name=:name, version=:version, binary=:binary, second_x_session=:second_x_session, additional_parameters=:additional_parameters WHERE name='" + op . old_profile . Name + "'" , & profile )
} else {
ctx . Database . Db . NamedExec ( "INSERT INTO urt_profiles (name, version, binary, second_x_session, additional_parameters) VALUES (:name, :version, :binary, :second_x_session, :additional_parameters)" , & profile )
}
}
}
op . loadProfiles ( )
op . window . Destroy ( )
}