/*
* File: appwnd.cc - Application window
* Project: GED - bitmap editor (ICP)
* Author: Kamil Dudka, xdudka00
* Team: xdudka00, xfilak01, xhefka00, xhradi08
* Created: 2006-03-12
*/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <list>
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Value_Slider.H>
#include <FL/Fl_Color_Chooser.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_PNG_Image.H>
#include "global.h"
#include "image.h"
#include "menu.h"
#include "gedconf.h"
#include "appwnd.h"
using std::string;
using GlobalH::szAppName;
using GlobalH::menuBarHeight;
namespace {
const BoxSize wndSize (400, 300);
void cb_wndProc (Fl_Widget *, void *)
{
AppWnd::ptr()->exit();
}
}
/*
* Initialize singleton AppWnd
*/
AppWnd *AppWnd::_instance = 0;
/*
* Sequence number for new documents
*/
int AppWnd::_iNewDocIterator = 1;
/*
* Global point to singleton AppWnd
*/
AppWnd *AppWnd::ptr ()
{
if (0== _instance)
_instance = new AppWnd;
return _instance;
}
/*
* This function should be called on program exit
*/
void AppWnd::destroy ()
{
if (0== _instance)
return;
_instance -> hide();
_instance -> clear();
Fl::delete_widget (_instance);
}
/*
* Return name for new document
*/
string AppWnd::newDocName ()
{
std::ostringstream name;
name << "new" << (_iNewDocIterator++) << ".png";
return name.str();
}
/*
* Add document "doc" to list
*/
void AppWnd::addDoc (Document *doc) {
#ifndef NDEBUG
std::cerr << "Added doc..\n";
#endif
_docList.push_back (doc);
_menu -> enableCloseAll (true);
}
/*
* Remove document "doc" from list
*/
void AppWnd::remDoc (Document *doc) {
#ifndef NDEBUG
std::cerr << "Deleted doc..\n";
#endif
_docList.remove (doc);
if (_docList.empty ())
_menu -> enableCloseAll (false);
}
/*
* Delete all documents
*/
bool AppWnd::closeAll () {
typedef std::list<Document *> TDocList;
typedef TDocList::iterator TDocListIter;
TDocList tmp = _docList;
for (TDocListIter i=tmp.begin(); i!=tmp.end(); i++) {
// Close doc (ask for save)
if (! ((*i)->tryClose () ))
// QueryEndSession canceled by user
return false;
}
return true;
}
/*
* Create main (app) window
*/
AppWnd::AppWnd ()
:Fl_Window (ToolSelect::width-1, ToolSelect::height + 8*menuBarHeight -1, szAppName),
_drawContext (TOOL_NOTOOL, 3, 8)
{
this->callback (cb_wndProc);
this->color (FL_DARK3);
this->begin ();
// Create menu
_menu = new AppMenu (Point(0, 0), BoxSize(ToolSelect::width, menuBarHeight));
_menu -> enableCloseAll (false);
// Create toolbar
_toolSelect = new ToolSelect (0, menuBarHeight, &(_drawContext.tool));
// Fg brush selection widget
_fgBrushSelect = new BrushSelect (
10, ToolSelect::height + 2*menuBarHeight,
ToolSelect::width-20, 2*menuBarHeight,
"Foreground brush",
&(_drawContext.fgBrushWidth),
&(_drawContext.fgColor));
// Bg brush selection widget
_bgBrushSelect = new BrushSelect (
10, ToolSelect::height + 5*menuBarHeight,
ToolSelect::width-20, 2*menuBarHeight,
"Background brush",
&(_drawContext.bgBrushWidth),
&(_drawContext.bgColor));
this->end ();
}
/*
* AppWnd destructor
*/
AppWnd::~AppWnd ()
{
_instance = 0;
}
/*
* Close all documents and exit
*/
void AppWnd::exit () {
if (!closeAll ())
return;
// Shutdown sequence
HelpBrowser::close ();
this->hide ();
this->clear ();
Fl::delete_widget (this);
}
/*
* Return true if window is maintained Document
*/
bool AppWnd::isDocument (Fl_Window *ptr)
{
return _docList.end()!= std::find (
_docList.begin(),
_docList.end(),
static_cast<Document *> (ptr));
}
/*
* Return current DrawTool
*/
DrawContext AppWnd::drawContext () const
{
return _drawContext;
}
/*
* Set current DrawTool
*/
void AppWnd::selectTool (EDrawTool et)
{
_drawContext.tool = et;
_toolSelect -> redraw ();
}
/*
* Create toolbar widget
*/
ToolSelect::ToolSelect (int x, int y, EDrawTool *dt):
Fl_Pack (x, y, width, height),
_drawTool (dt)
{
begin();
Fl_Button **pButt = _tbButt;
Fl_PNG_Image **pIcon = _tbIcon;
for (int currRow = 0; currRow < iRowCnt; currRow++) {
// Create one line of toolbar
Fl_Pack *line = new Fl_Pack (0, 0, iColCnt * iButtonSize, iButtonSize);
line -> type (FL_HORIZONTAL);
line -> begin();
// Create buttons
for (int currCol = 0; currCol < iColCnt; currCol++, pButt++, pIcon++) {
// Button text
const char *szText = DrawContext::toolLabel(
static_cast<EDrawTool>(pButt-_tbButt+1));
// Draw button
*pButt = new Fl_Button (0, 0, iButtonSize, iButtonSize, szText);
(*pButt) -> callback (cb_button, this);
(*pButt) -> color (FL_WHITE);
// Obtain image name
std::string iconFile = GedConf::ptr()->getImageDir() + "/" + szText +".png";
// Test if file exists
std::fstream file (iconFile.c_str(), std::ios::in);
if (file) {
file.close ();
// Load image and draw icon
*pIcon = new Fl_PNG_Image (iconFile.c_str());
(*pButt) -> image (*pIcon);
} else
*pIcon = 0;
}
line -> end();
}
end();
}
/*
* Toolbar destructor
*/
ToolSelect::~ToolSelect ()
{
this->hide ();
this->clear ();
for (int i=0; i<iButtonCnt; i++)
delete _tbIcon [i];
}
/*
* Toolbar button callback
*/
void ToolSelect::cb_button (Fl_Widget *widget, void *data)
{
Fl_Button *pButt = static_cast<Fl_Button *>(widget);
ToolSelect *const pTB = static_cast<ToolSelect *>(data);
pTB->setTool (pButt);
pTB->redraw ();
}
/*
* Set tool corresponding to button "butt"
*/
void ToolSelect::setTool (Fl_Button *butt)
{
int i=0;
for (Fl_Button **scan = _tbButt; *scan != butt; scan++, i++)
if (i>=iButtonCnt)
// Critical internal error
throw;
*_drawTool = static_cast<EDrawTool>(i+1);
}
/*
* Redraw toolbar widget
*/
void ToolSelect::redraw ()
{
for (int i=0; i<iButtonCnt; i++)
_tbButt [i] -> value ( i+1==*_drawTool ? 1:0);
Fl_Pack::redraw ();
}
/*
* Create brush selection widget
*/
BrushSelect::BrushSelect (int x, int y, int width, int height, const char *szTitle, int *pBrushSize, Pixel *pBrushColor):
Fl_Pack (x, y, width, height),
_pBrushSize (pBrushSize),
_pBrushColor (pBrushColor)
{
begin();
_pButt = new Fl_Button (x, y, width, menuBarHeight, szTitle);
_pButt->callback (cb_button, this);
setButtonColor ();
_pVal = new Fl_Value_Slider (x, y+menuBarHeight, width, menuBarHeight);
_pVal->callback (cb_valuator, this);
_pVal->type (FL_HORIZONTAL);
_pVal->bounds (1.0,10.0);
_pVal->precision (0);
_pVal->value (static_cast<double> (*_pBrushSize));
end();
}
/*
* Destroy brush selection widget
*/
BrushSelect::~BrushSelect ()
{
this->hide ();
this->clear ();
}
/*
* Ask user for color
*/
void BrushSelect::askForColor ()
{
fl_color_chooser ("Set brush color",
_pBrushColor->red, _pBrushColor->green, _pBrushColor->blue);
setButtonColor ();
}
/*
* Set button color to selected color
*/
void BrushSelect::setButtonColor () {
_pButt->color (fl_rgb_color (
_pBrushColor->red,
_pBrushColor->green,
_pBrushColor->blue));
_pButt->labelcolor (fl_rgb_color (
0xFF - _pBrushColor->red,
0xFF - _pBrushColor->green,
0xFF - _pBrushColor->blue));
}
/*
* Read brush width from valuator
*/
void BrushSelect::readBrushWidht ()
{
*_pBrushSize = static_cast<int> (_pVal->value ());
}
/*
* Brush selection widget button callback
*/
void BrushSelect::cb_button (Fl_Widget *, void *data)
{
BrushSelect *const pBS = static_cast<BrushSelect *>(data);
pBS->askForColor ();
}
/*
* Brush selection widget valuator callback
*/
void BrushSelect::cb_valuator (Fl_Widget *, void *data)
{
BrushSelect *const pBS = static_cast<BrushSelect *>(data);
pBS->readBrushWidht ();
}