src/configDialog.cpp

Tue, 16 Jul 2013 02:47:11 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Tue, 16 Jul 2013 02:47:11 +0300
changeset 392
629e3142d02d
parent 386
751d31336f08
child 395
5210bcb1d7e0
permissions
-rw-r--r--

change camera to top if switching to draw mode in free camera

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013 Santeri Piippo
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <QGridLayout>
#include <QFileDialog>
#include <QColorDialog>
#include <QBoxLayout>
#include <QKeyEvent>
#include <QGroupBox>
#include <QDoubleSpinBox>
#include <QLineEdit>
#include <QCheckBox>

#include "common.h"
#include "configDialog.h"
#include "file.h"
#include "config.h"
#include "misc.h"
#include "colors.h"
#include "colorSelectDialog.h"
#include "gldraw.h"
#include "ui_config.h"

extern_cfg (str, gl_bgcolor);
extern_cfg (str, gl_maincolor);
extern_cfg (bool, lv_colorize);
extern_cfg (bool, gl_colorbfc);
extern_cfg (float, gl_maincolor_alpha);
extern_cfg (int, gl_linethickness);
extern_cfg (int, gui_toolbar_iconsize);
extern_cfg (str, gui_colortoolbar);
extern_cfg (bool, edit_schemanticinline);
extern_cfg (bool, gl_blackedges);

#define act(N) extern_cfg (keyseq, key_##N);
#include "actions.h"

#define INIT_CHECKBOX(BOX, CFG) \
	BOX->setCheckState (CFG ? Qt::Checked : Qt::Unchecked);

#define APPLY_CHECKBOX(BTN, CFG) \
	CFG = BTN->checkState() == Qt::Checked;

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
ConfigDialog::ConfigDialog (ForgeWindow* parent) : QDialog (parent) {
	ui = new Ui_ConfigUI;
	ui->setupUi( this );
	
	initMainTab ();
	initShortcutsTab ();
	initQuickColorTab ();
	initGridTab ();
	initExtProgTab ();
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
ConfigDialog::~ConfigDialog()
{
	delete ui;
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::initMainTab () {
	// Init color stuff
	setButtonBackground (ui->backgroundColorButton, gl_bgcolor);
	connect (ui->backgroundColorButton, SIGNAL (clicked ()),
		this, SLOT (slot_setGLBackground ()));
	
	setButtonBackground (ui->mainColorButton, gl_maincolor.value);
	connect (ui->mainColorButton, SIGNAL (clicked ()),
		this, SLOT (slot_setGLForeground ()));
	
	ui->mainColorAlpha->setValue( gl_maincolor_alpha * 10.0f );
	
	// Sliders
	ui->lineThickness->setValue( gl_linethickness );
	ui->iconSize->setValue(( gui_toolbar_iconsize - 12 ) / 4 );
	
	// Checkboxes
	ui->colorizeObjects->setChecked( lv_colorize );
	ui->colorBFC->setChecked( gl_colorbfc );
	ui->blackEdges->setChecked (gl_blackedges);
	ui->scemanticInlining->setChecked (edit_schemanticinline);
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::initShortcutsTab () {
	ulong i = 0;
	
#define act(N) addShortcut (key_##N, ACTION(N), i);
#include "actions.h"
	
	ui->shortcutsList->setSortingEnabled( true );
	ui->shortcutsList->sortItems();
	
	connect( ui->shortcut_set, SIGNAL( clicked() ), this, SLOT( slot_setShortcut() ));
	connect( ui->shortcut_reset, SIGNAL( clicked() ), this, SLOT( slot_resetShortcut() ));
	connect( ui->shortcut_clear, SIGNAL( clicked() ), this, SLOT( slot_clearShortcut() ));
}

void ConfigDialog::addShortcut (keyseqconfig& cfg, QAction* act, ulong& i) {
	ShortcutListItem* item = new ShortcutListItem;
	item->setIcon (act->icon());
	item->setKeyConfig (&cfg);
	item->setAction (act);
	setShortcutText (item);
	
	// If the action doesn't have a valid icon, use an empty one
	// so that the list is kept aligned.
	if (act->icon().isNull())
		item->setIcon (getIcon ("empty"));
	
	ui->shortcutsList->insertItem (i++, item);
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::initQuickColorTab()
{
	quickColorMeta = parseQuickColorMeta();
	updateQuickColorList();

	connect( ui->quickColor_add, SIGNAL( clicked() ), this, SLOT( slot_setColor() ));
	connect( ui->quickColor_remove, SIGNAL( clicked() ), this, SLOT( slot_delColor() ));
	connect( ui->quickColor_edit, SIGNAL( clicked() ), this, SLOT( slot_setColor() ));
	connect( ui->quickColor_addSep, SIGNAL( clicked() ), this, SLOT( slot_addColorSeparator() ));
	connect( ui->quickColor_moveUp, SIGNAL( clicked() ), this, SLOT( slot_moveColor() ));
	connect( ui->quickColor_moveDown, SIGNAL( clicked() ), this, SLOT( slot_moveColor() ));
	connect( ui->quickColor_clear, SIGNAL( clicked() ), this, SLOT( slot_clearColors() ));
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::initGridTab()
{
	QGridLayout* gridlayout = new QGridLayout;

	QLabel* xlabel = new QLabel( "X" ),
		*ylabel = new QLabel( "Y" ),
		*zlabel = new QLabel( "Z" ),
		*anglabel = new QLabel( "Angle" );

	short i = 1;
	
	for( QLabel* label : initlist<QLabel*> ({ xlabel, ylabel, zlabel, anglabel }))
	{
		label->setAlignment( Qt::AlignCenter );
		gridlayout->addWidget( label, 0, i++ );
	}
	
	for( int i = 0; i < g_NumGrids; ++i )
	{
		// Icon
		lb_gridIcons[i] = new QLabel;
		lb_gridIcons[i]->setPixmap( getIcon( fmt( "grid-%1", str( g_GridInfo[i].name ).toLower() )));
		
		// Text label
		lb_gridLabels[i] = new QLabel( fmt( "%1:", g_GridInfo[i].name ));
		
		QHBoxLayout* labellayout = new QHBoxLayout;
		labellayout->addWidget( lb_gridIcons[i] );
		labellayout->addWidget( lb_gridLabels[i] );
		gridlayout->addLayout( labellayout, i + 1, 0 );
		
		// Add the widgets
		for( int j = 0; j < 4; ++j )
		{
			dsb_gridData[i][j] = new QDoubleSpinBox;
			dsb_gridData[i][j]->setValue( g_GridInfo[i].confs[j]->value );
			gridlayout->addWidget( dsb_gridData[i][j], i + 1, j + 1 );
		}
	}
	
	ui->grids->setLayout( gridlayout );
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
extern_cfg( str, prog_ytruder );
extern_cfg( str, prog_rectifier );
extern_cfg( str, prog_intersector );
extern_cfg( str, prog_coverer );
extern_cfg( str, prog_isecalc );
extern_cfg( str, prog_edger2 );
extern_cfg( bool, prog_ytruder_wine );
extern_cfg( bool, prog_rectifier_wine );
extern_cfg( bool, prog_intersector_wine );
extern_cfg( bool, prog_coverer_wine );
extern_cfg( bool, prog_isecalc_wine );
extern_cfg( bool, prog_edger2_wine );

static const struct extProgInfo
{
	const str name, iconname;
	strconfig* const path;
	mutable QLineEdit* input;
	mutable QPushButton* setPathButton;
#ifndef _WIN32
	boolconfig* const wine;
	mutable QCheckBox* wineBox;
#endif // _WIN32
} g_extProgInfo[] = {
#ifndef _WIN32
# define EXTPROG( NAME, LOWNAME ) { #NAME, #LOWNAME, &prog_##LOWNAME, null, null, &prog_##LOWNAME##_wine, null },
#else
# define EXTPROG( NAME, LOWNAME ) { #NAME, #LOWNAME, &prog_##LOWNAME, null, null },
#endif
	EXTPROG( Ytruder, ytruder )
	EXTPROG( Rectifier, rectifier )
	EXTPROG( Intersector, intersector )
	EXTPROG( Isecalc, isecalc )
	EXTPROG( Coverer, coverer )
	EXTPROG( Edger2, edger2 )
#undef EXTPROG
};

void ConfigDialog::initExtProgTab()
{
	QGridLayout* pathsLayout = new QGridLayout;
	ulong row = 0;
	
	for( const extProgInfo & info : g_extProgInfo )
	{
		QLabel* icon = new QLabel,
		*progLabel = new QLabel( info.name );
		QLineEdit* input = new QLineEdit;
		QPushButton* setPathButton = new QPushButton;
		
		icon->setPixmap( getIcon( info.iconname ));
		input->setText( info.path->value );
		setPathButton->setIcon( getIcon( "folder" ));
		info.input = input;
		info.setPathButton = setPathButton;
		
		connect( setPathButton, SIGNAL( clicked() ), this, SLOT( slot_setExtProgPath() ));
		
		pathsLayout->addWidget( icon, row, 0 );
		pathsLayout->addWidget( progLabel, row, 1 );
		pathsLayout->addWidget( input, row, 2 );
		pathsLayout->addWidget( setPathButton, row, 3 );
		
#ifndef _WIN32
		QCheckBox* wineBox = new QCheckBox( "Wine" );
		wineBox->setChecked( *info.wine );
		info.wineBox = wineBox;
		pathsLayout->addWidget( wineBox, row, 4 );
#endif
		
		++row;
	}
	
	ui->extProgs->setLayout( pathsLayout );
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::updateQuickColorList( quickColor* sel )
{
	for( QListWidgetItem* item : quickColorItems )
		delete item;
	
	quickColorItems.clear();
	
	// Init table items
	for( quickColor& entry : quickColorMeta )
	{
		QListWidgetItem* item = new QListWidgetItem;
		
		if( entry.isSeparator )
		{
			item->setText( "--------" );
			item->setIcon( getIcon( "empty" ));
		}
		else
		{
			LDColor* col = entry.col;
			
			if( col == null )
			{
				item->setText( "[[unknown color]]" );
				item->setIcon( getIcon( "error" ));
			}
			else
			{
				item->setText( col->name );
				item->setIcon( makeColorIcon( col, 16 ));
			}
		}
		
		ui->quickColorList->addItem( item );
		quickColorItems << item;
		
		if( sel && &entry == sel )
		{
			ui->quickColorList->setCurrentItem( item );
			ui->quickColorList->scrollToItem( item );
		}
	}
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::slot_setColor()
{
	quickColor* entry = null;
	QListWidgetItem* item = null;
	const bool isNew = static_cast<QPushButton*>( sender() ) == ui->quickColor_add;

	if( isNew == false )
	{
		item = getSelectedQuickColor();
		
		if( !item )
			return;
		
		ulong i = getItemRow( item, quickColorItems );
		entry = &quickColorMeta[i];
		
		if( entry->isSeparator == true )
			return; // don't color separators
	}
	
	short defval = entry ? entry->col->index : -1;
	short val;
	
	if( ColorSelector::getColor( val, defval, this ) == false )
		return;
	
	if( entry )
		entry->col = getColor( val );
	else
	{
		quickColor entry = {getColor( val ), null, false};
		
		item = getSelectedQuickColor();
		ulong idx;
		
		if( item )
			idx = getItemRow( item, quickColorItems ) + 1;
		else
			idx = quickColorItems.size();
		
		quickColorMeta.insert( idx, entry );
		entry = quickColorMeta[idx];
	}
	
	updateQuickColorList( entry );
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::slot_delColor()
{
	if( ui->quickColorList->selectedItems().size() == 0 )
		return;

	QListWidgetItem* item = ui->quickColorList->selectedItems()[0];
	quickColorMeta.erase( getItemRow( item, quickColorItems ));
	updateQuickColorList();
}

// =============================================================================
void ConfigDialog::slot_moveColor()
{
	const bool up = ( static_cast<QPushButton*>( sender() ) == ui->quickColor_moveUp );
	
	if( ui->quickColorList->selectedItems().size() == 0 )
		return;
	
	QListWidgetItem* item = ui->quickColorList->selectedItems()[0];
	int idx = getItemRow( item, quickColorItems );
	int dest = up ? ( idx - 1 ) : ( idx + 1 );
	
	if( dest < 0 || ( ulong ) dest >= quickColorItems.size() )
		return; // destination out of bounds
	
	quickColor tmp = quickColorMeta[dest];
	quickColorMeta[dest] = quickColorMeta[idx];
	quickColorMeta[idx] = tmp;
	
	updateQuickColorList( &quickColorMeta[dest] );
}

// =============================================================================
void ConfigDialog::slot_addColorSeparator()
{
	quickColorMeta << quickColor({ null, null, true });
	updateQuickColorList( &quickColorMeta[quickColorMeta.size() - 1] );
}

// =============================================================================
void ConfigDialog::slot_clearColors()
{
	quickColorMeta.clear();
	updateQuickColorList();
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::pickColor( strconfig& conf, QPushButton* button )
{
	QColor col = QColorDialog::getColor( QColor( conf ));

	if( col.isValid() )
	{
		uchar r = col.red(),
			  g = col.green(),
			  b = col.blue();
		conf.value.sprintf( "#%.2X%.2X%.2X", r, g, b );
		setButtonBackground( button, conf.value );
	}
}

void ConfigDialog::slot_setGLBackground()
{
	pickColor( gl_bgcolor, ui->backgroundColorButton );
}

void ConfigDialog::slot_setGLForeground()
{
	pickColor( gl_maincolor, ui->mainColorButton );
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::setButtonBackground( QPushButton* button, str value )
{
	button->setIcon( getIcon( "colorselect" ));
	button->setAutoFillBackground( true );
	button->setStyleSheet( fmt( "background-color: %1", value ));
}

// =============================================================================
int ConfigDialog::getItemRow( QListWidgetItem* item, vector<QListWidgetItem*>& haystack )
{
	int i = 0;
	
	for( QListWidgetItem * it : haystack )
	{
		if( it == item )
			return i;
		
		++i;
	}
	
	return -1;
}

// =============================================================================
QListWidgetItem* ConfigDialog::getSelectedQuickColor()
{
	if( ui->quickColorList->selectedItems().size() == 0 )
		return null;
	
	return ui->quickColorList->selectedItems()[0];
}

// =============================================================================
QList<ShortcutListItem*> ConfigDialog::getShortcutSelection()
{
	QList<ShortcutListItem*> out;
	
	for( QListWidgetItem * entry : ui->shortcutsList->selectedItems() )
		out << static_cast<ShortcutListItem*>( entry );
	
	return out;
}

// =============================================================================
void ConfigDialog::slot_setShortcut()
{
	QList<ShortcutListItem*> sel = getShortcutSelection();
	
	if( sel.size() < 1 )
		return;
	
	ShortcutListItem* item = sel[0];
	
	if (KeySequenceDialog::staticDialog (item->keyConfig(), this))
		setShortcutText (item);
}

// =============================================================================
void ConfigDialog::slot_resetShortcut()
{
	QList<ShortcutListItem*> sel = getShortcutSelection();
	
	for (ShortcutListItem* item : sel) {
		item->keyConfig()->reset();
		setShortcutText (item);
	}
}

// =============================================================================
void ConfigDialog::slot_clearShortcut() {
	QList<ShortcutListItem*> sel = getShortcutSelection();
	
	for (ShortcutListItem* item : sel) {
		item->keyConfig()->value = QKeySequence();
		setShortcutText (item);
	}
}

// =============================================================================
void ConfigDialog::slot_setExtProgPath() {
	const extProgInfo* info = null;
	
	for (const extProgInfo& it : g_extProgInfo) {
		if (it.setPathButton == sender()) {
			info = &it;
			break;
		}
	}
	
	assert (info != null);
	
	str filter;
#ifdef _WIN32
	filter = "Applications (*.exe)(*.exe);;All files (*.*)(*.*)";
#endif // WIN32
	
	str fpath = QFileDialog::getOpenFileName( this, fmt( "Path to %1", info->name ), *info->path, filter );
	
	if( fpath.length() == 0 )
		return;
	
	info->input->setText( fpath );
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::setShortcutText( ShortcutListItem* item ) {
	QAction* act = item->action();
	str label = act->iconText();
	str keybind = item->keyConfig()->value.toString();
	
	item->setText (fmt ("%1 (%2)", label, keybind));
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
str ConfigDialog::makeColorToolBarString()
{
	str val;
	
	for( quickColor entry : quickColorMeta )
	{
		if( val.length() > 0 )
			val += ':';
		
		if( entry.isSeparator )
			val += '|';
		else
			val += fmt( "%1", entry.col->index );
	}
	
	return val;
}

const Ui_ConfigUI* ConfigDialog::getUI() const
{
	return ui;
}

float ConfigDialog::getGridValue( int i, int j ) const
{
	return dsb_gridData[i][j]->value();
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void ConfigDialog::staticDialog()
{
	ConfigDialog dlg( g_win );
	
	if( dlg.exec() )
	{
		// Apply configuration
		lv_colorize = dlg.getUI()->colorizeObjects->isChecked();
		gl_colorbfc = dlg.getUI()->colorBFC->isChecked();
		edit_schemanticinline = dlg.getUI()->scemanticInlining->isChecked();
		gl_blackedges = dlg.getUI()->blackEdges->isChecked();
		gl_maincolor_alpha = ( ( double )dlg.getUI()->mainColorAlpha->value() ) / 10.0f;
		gl_linethickness = dlg.getUI()->lineThickness->value();
		gui_toolbar_iconsize = ( dlg.getUI()->iconSize->value() * 4 ) + 12;
		
		// Manage the quick color toolbar
		g_win->setQuickColorMeta( dlg.quickColorMeta );
		gui_colortoolbar = dlg.makeColorToolBarString();
		
		// Set the grid settings
		for( int i = 0; i < g_NumGrids; ++i )
			for( int j = 0; j < 4; ++j )
				g_GridInfo[i].confs[j]->value = dlg.getGridValue( i, j );
		
		// Apply key shortcuts
#define act(N) ACTION(N)->setShortcut (key_##N);
#include "actions.h"
		
		// Ext program settings
		for( const extProgInfo & info : g_extProgInfo )
		{
			*info.path = info.input->text();
			
#ifndef _WIN32
			*info.wine = info.wineBox->isChecked();
#endif // _WIN32
		}
		
		// Save the config
		config::save();
		
		// Reload all subfiles as the ldraw path potentially changed.
		reloadAllSubfiles();
		
		g_win->R()->setBackground();
		g_win->fullRefresh();
		g_win->updateToolBars();
	}
}

// =========================================================================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =========================================================================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =========================================================================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =========================================================================================================================
KeySequenceDialog::KeySequenceDialog( QKeySequence seq, QWidget* parent, Qt::WindowFlags f ) :
	QDialog( parent, f ), seq( seq )
{
	lb_output = new QLabel;
	IMPLEMENT_DIALOG_BUTTONS
	
	setWhatsThis( "Into this dialog you can input a key sequence for use as a "
		"shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to "
		"dismiss." );
	
	QVBoxLayout* layout = new QVBoxLayout;
	layout->addWidget( lb_output );
	layout->addWidget( bbx_buttons );
	setLayout( layout );
	
	updateOutput();
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
bool KeySequenceDialog::staticDialog (keyseqconfig* cfg, QWidget* parent) {
	KeySequenceDialog dlg (cfg->value, parent);
	
	if (dlg.exec() == false)
		return false;
	
	cfg->value = dlg.seq;
	return true;
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void KeySequenceDialog::updateOutput()
{
	str shortcut = seq.toString();
	
	if( seq == QKeySequence() )
		shortcut = "&lt;empty&gt;";
	
	str text = fmt( "<center><b>%1</b></center>", shortcut );
	
	lb_output->setText( text );
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void KeySequenceDialog::keyPressEvent( QKeyEvent* ev )
{
	seq = ev->key() + ev->modifiers();
	updateOutput();
}

mercurial