Refactoring FLabel::draw and FFileDialog::readDir

This commit is contained in:
Markus Gans 2018-01-30 00:11:58 +01:00
parent 7eb6bfa587
commit 10275c0953
6 changed files with 366 additions and 292 deletions

View File

@ -1,3 +1,7 @@
2017-01-30 Markus Gans <guru.mail@muenster.de>
* Refactoring FLabel::draw
* Refactoring FFileDialog::readDir
2017-01-28 Markus Gans <guru.mail@muenster.de>
* Refactoring FApplication::processKeyboardEvent
* Shorter methods and a fix for recreating new windows

View File

@ -277,6 +277,10 @@ class MyDialog : public FDialog
void initStatusBar();
void initStatusBarCallbacks();
void initWidgets();
void initFlatButtons();
void initToggleButtons();
void initButtons();
void initLabels();
void initWidgetsCallbacks();
void adjustSize();
@ -531,7 +535,7 @@ void MyDialog::initStatusBar()
//----------------------------------------------------------------------
void MyDialog::initStatusBarCallbacks()
{
// Add some function callbacks
// Add statusbar function callbacks
key_F1->addCallback
(
@ -555,7 +559,40 @@ void MyDialog::initStatusBarCallbacks()
//----------------------------------------------------------------------
void MyDialog::initWidgets()
{
// Flat buttons
initFlatButtons();
// Radio buttons and check boxes
initToggleButtons();
// A text input field
myLineEdit = new FLineEdit (this);
myLineEdit->setGeometry(22, 1, 10, 1);
myLineEdit->setLabelText (L"&Input");
myLineEdit->setStatusbarMessage ("Press Enter to set the title");
*myLineEdit << FString("EnTry").toLower();
// Buttons
initButtons();
// A multiple selection listbox
myList = new FListBox (this);
myList->setGeometry(38, 1, 14, 17);
myList->setText ("Items");
myList->setStatusbarMessage ("99 items in a list");
myList->setMultiSelection();
for (int z = 1; z < 100; z++)
myList->insert (FString() << z << L" placeholder");
// Text labels
initLabels();
}
//----------------------------------------------------------------------
void MyDialog::initFlatButtons()
{
// Flat buttons
MyButton1 = new FButton (this);
MyButton1->setGeometry(3, 3, 5, 1);
MyButton1->setText (L"&SIN");
@ -579,6 +616,29 @@ void MyDialog::initWidgets()
MyButton3->setNoUnderline();
MyButton3->setFlat();
// Add button callback functions
MyButton1->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_noFunctionMsg)
);
MyButton2->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_noFunctionMsg)
);
MyButton3->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_noFunctionMsg)
);
}
//----------------------------------------------------------------------
void MyDialog::initToggleButtons()
{
// Radio buttons in a group
FButtonGroup* radioButtonGroup = new FButtonGroup ("Button", this);
radioButtonGroup->setGeometry(3, 8, 14, 4);
@ -607,14 +667,11 @@ void MyDialog::initWidgets()
check2->setGeometry(1, 2, 9, 1);
check2->setChecked();
check2->setNoUnderline();
}
// A text input field
myLineEdit = new FLineEdit (this);
myLineEdit->setGeometry(22, 1, 10, 1);
myLineEdit->setLabelText (L"&Input");
myLineEdit->setStatusbarMessage ("Press Enter to set the title");
*myLineEdit << FString("EnTry").toLower();
//----------------------------------------------------------------------
void MyDialog::initButtons()
{
// Buttons
MyButton4 = new FButton (this);
MyButton4->setGeometry(20, 8, 12, 1);
@ -634,16 +691,30 @@ void MyDialog::initWidgets()
MyButton6->setStatusbarMessage ("Exit the program");
MyButton6->addAccelerator('x');
// A multiple selection listbox
myList = new FListBox (this);
myList->setGeometry(38, 1, 14, 17);
myList->setText ("Items");
myList->setStatusbarMessage ("99 items in a list");
myList->setMultiSelection();
// Add button callback functions
MyButton4->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_input2buttonText),
static_cast<FWidget::data_ptr>(myLineEdit)
);
for (int z = 1; z < 100; z++)
myList->insert (FString() << z << L" placeholder");
MyButton5->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_ProgressBar)
);
MyButton6->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &FApplication::cb_exitApp)
);
}
//----------------------------------------------------------------------
void MyDialog::initLabels()
{
// Text labels
FLabel* headline = new FLabel (this);
headline->setGeometry(21, 3, 10, 1);
@ -672,43 +743,6 @@ void MyDialog::initWidgetsCallbacks()
{
// Add some function callbacks
MyButton1->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_noFunctionMsg)
);
MyButton2->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_noFunctionMsg)
);
MyButton3->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_noFunctionMsg)
);
MyButton4->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_input2buttonText),
static_cast<FWidget::data_ptr>(myLineEdit)
);
MyButton5->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &MyDialog::cb_ProgressBar)
);
MyButton6->addCallback
(
"clicked",
F_METHOD_CALLBACK (this, &FApplication::cb_exitApp)
);
myLineEdit->addCallback
(
"activate", // e.g. on <Enter>

View File

@ -3,7 +3,7 @@
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2014-2017 Markus Gans *
* Copyright 2014-2018 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
@ -130,7 +130,6 @@ class FFileDialog : public FDialog
void onKeyPress (FKeyEvent*);
// Methods
int readDir();
static const FString fileOpenChooser ( FWidget*
, const FString& = FString()
, const FString& = FString() );
@ -166,6 +165,10 @@ class FFileDialog : public FDialog
void clear();
int numOfDirs();
void sortDir();
int readDir();
void getEntry (struct dirent*);
void followSymLink (dir_entry&);
void dirEntriesToList();
int changeDir (const FString&);
void printPath (const FString&);
static const FString getHomeDir();

View File

@ -3,7 +3,7 @@
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2014-2017 Markus Gans *
* Copyright 2014-2018 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
@ -141,8 +141,10 @@ class FLabel : public FWidget
int getHotkeyPos (wchar_t[], wchar_t[], uInt);
void setHotkeyAccelerator();
int getAlignOffset (int);
void printLine (wchar_t[], uInt, int, int = 0);
void draw();
void drawMultiLine();
void drawSingleLine();
void printLine (wchar_t[], uInt, int, int = 0);
// Data Members
FStringList multiline_text;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2014-2017 Markus Gans *
* Copyright 2014-2018 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
@ -254,136 +254,6 @@ void FFileDialog::onKeyPress (FKeyEvent* ev)
}
}
//----------------------------------------------------------------------
int FFileDialog::readDir()
{
const char* const dir = directory.c_str();
const char* const filter = filter_pattern.c_str();
directory_stream = opendir(dir);
if ( ! directory_stream )
{
FMessageBox::error (this, "Can't open directory\n" + directory);
return -1;
}
clear();
while ( true )
{
errno = 0;
struct dirent* next = readdir(directory_stream);
if ( next )
{
if ( next->d_name[0] == '.' && next->d_name[1] == '\0' )
continue;
if ( ! show_hidden
&& next->d_name[0] == '.'
&& next->d_name[1] != '\0'
&& next->d_name[1] != '.' )
{
continue;
}
if ( dir[0] == '/' && dir[1] == '\0'
&& std::strcmp(next->d_name, "..") == 0 )
continue;
dir_entry entry;
entry.name = strdup(next->d_name);
#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
entry.fifo = (next->d_type & DT_FIFO) == DT_FIFO;
entry.character_device = (next->d_type & DT_CHR ) == DT_CHR;
entry.directory = (next->d_type & DT_DIR ) == DT_DIR;
entry.block_device = (next->d_type & DT_BLK ) == DT_BLK;
entry.regular_file = (next->d_type & DT_REG ) == DT_REG;
entry.symbolic_link = (next->d_type & DT_LNK ) == DT_LNK;
entry.socket = (next->d_type & DT_SOCK) == DT_SOCK;
#else
struct stat s;
stat (entry.name, &s);
entry.fifo = S_ISFIFO (s.st_mode);
entry.character_device = S_ISCHR (s.st_mode);
entry.directory = S_ISDIR (s.st_mode);
entry.block_device = S_ISBLK (s.st_mode);
entry.regular_file = S_ISREG (s.st_mode);
entry.symbolic_link = S_ISLNK (s.st_mode);
entry.socket = S_ISSOCK (s.st_mode);
#endif
if ( entry.symbolic_link ) // symbolic link
{
char resolved_path[MAXPATHLEN] = {};
char symLink[MAXPATHLEN] = {};
std::strncpy (symLink, dir, sizeof(symLink) - 1);
std::strncat ( symLink
, next->d_name
, sizeof(symLink) - std::strlen(symLink) - 1);
if ( realpath(symLink, resolved_path) != 0 ) // follow link
{
struct stat sb;
if ( lstat(resolved_path, &sb) == 0 )
{
if ( S_ISDIR(sb.st_mode) )
entry.directory = true;
}
}
}
if ( entry.directory )
dir_entries.push_back (entry);
else if ( pattern_match(filter, entry.name) )
dir_entries.push_back (entry);
else
std::free(entry.name);
}
else if ( errno != 0 )
{
FMessageBox::error (this, "Reading directory\n" + directory);
if ( errno == EOVERFLOW ) // Value too large to be stored in data type
break;
}
else
break;
} // end while
if ( closedir(directory_stream) != 0 )
{
FMessageBox::error (this, "Closing directory\n" + directory);
return -2;
}
sortDir();
// fill list with directory entries
filebrowser->clear();
if ( ! dir_entries.empty() )
{
std::vector<dir_entry>::const_iterator iter, last;
iter = dir_entries.begin();
last = dir_entries.end();
while ( iter != last )
{
if ( (*iter).directory )
filebrowser->insert(FString((*iter).name), fc::SquareBrackets);
else
filebrowser->insert(FString((*iter).name));
++iter;
}
}
return 0;
}
//----------------------------------------------------------------------
const FString FFileDialog::fileOpenChooser ( FWidget* parent
, const FString& dirname
@ -701,6 +571,159 @@ void FFileDialog::sortDir()
, sortByName );
}
//----------------------------------------------------------------------
int FFileDialog::readDir()
{
const char* const dir = directory.c_str();
directory_stream = opendir(dir);
if ( ! directory_stream )
{
FMessageBox::error (this, "Can't open directory\n" + directory);
return -1;
}
clear();
while ( true )
{
errno = 0;
struct dirent* next = readdir(directory_stream);
if ( next )
{
// Continue if name = "." (current directory)
if ( next->d_name[0] == '.' && next->d_name[1] == '\0' )
continue;
// Skip hidden entries
if ( ! show_hidden
&& next->d_name[0] == '.'
&& next->d_name[1] != '\0'
&& next->d_name[1] != '.' )
continue;
// Skip ".." for the root directory
if ( dir[0] == '/' && dir[1] == '\0'
&& std::strcmp(next->d_name, "..") == 0 )
continue;
getEntry(next);
}
else if ( errno != 0 )
{
FMessageBox::error (this, "Reading directory\n" + directory);
if ( errno == EOVERFLOW ) // Value too large to be stored in data type
break;
}
else
break;
} // end while
if ( closedir(directory_stream) != 0 )
{
FMessageBox::error (this, "Closing directory\n" + directory);
return -2;
}
sortDir();
// Insert directory entries into the list
dirEntriesToList();
return 0;
}
//----------------------------------------------------------------------
void FFileDialog::getEntry (struct dirent* d_entry)
{
const char* const filter = filter_pattern.c_str();
dir_entry entry;
entry.name = strdup(d_entry->d_name);
#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
entry.fifo = (d_entry->d_type & DT_FIFO) == DT_FIFO;
entry.character_device = (d_entry->d_type & DT_CHR ) == DT_CHR;
entry.directory = (d_entry->d_type & DT_DIR ) == DT_DIR;
entry.block_device = (d_entry->d_type & DT_BLK ) == DT_BLK;
entry.regular_file = (d_entry->d_type & DT_REG ) == DT_REG;
entry.symbolic_link = (d_entry->d_type & DT_LNK ) == DT_LNK;
entry.socket = (d_entry->d_type & DT_SOCK) == DT_SOCK;
#else
struct stat s;
stat (entry.name, &s);
entry.fifo = S_ISFIFO (s.st_mode);
entry.character_device = S_ISCHR (s.st_mode);
entry.directory = S_ISDIR (s.st_mode);
entry.block_device = S_ISBLK (s.st_mode);
entry.regular_file = S_ISREG (s.st_mode);
entry.symbolic_link = S_ISLNK (s.st_mode);
entry.socket = S_ISSOCK (s.st_mode);
#endif
followSymLink(entry);
if ( entry.directory )
dir_entries.push_back (entry);
else if ( pattern_match(filter, entry.name) )
dir_entries.push_back (entry);
else
std::free(entry.name);
}
//----------------------------------------------------------------------
void FFileDialog::followSymLink (dir_entry& entry)
{
if ( ! entry.symbolic_link )
return; // No symbolic link
char resolved_path[MAXPATHLEN] = {};
char symLink[MAXPATHLEN] = {};
struct stat sb;
const char* const dir = directory.c_str();
std::strncpy (symLink, dir, sizeof(symLink) - 1);
std::strncat ( symLink
, entry.name
, sizeof(symLink) - std::strlen(symLink) - 1);
if ( realpath(symLink, resolved_path) == 0 )
return; // Cannot follow the symlink
if ( lstat(resolved_path, &sb) == -1 )
return; // Cannot get file status
if ( S_ISDIR(sb.st_mode) )
entry.directory = true;
}
//----------------------------------------------------------------------
void FFileDialog::dirEntriesToList()
{
// Fill list with directory entries
filebrowser->clear();
if ( dir_entries.empty() )
return;
std::vector<dir_entry>::const_iterator iter, last;
iter = dir_entries.begin();
last = dir_entries.end();
while ( iter != last )
{
if ( (*iter).directory )
filebrowser->insert(FString((*iter).name), fc::SquareBrackets);
else
filebrowser->insert(FString((*iter).name));
++iter;
}
}
//----------------------------------------------------------------------
int FFileDialog::changeDir (const FString& dirname)
{

View File

@ -3,7 +3,7 @@
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2014-2017 Markus Gans *
* Copyright 2014-2018 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
@ -486,6 +486,117 @@ int FLabel::getAlignOffset (int length)
return 0;
}
//----------------------------------------------------------------------
void FLabel::draw()
{
if ( isMonochron() )
{
setReverse(true);
if ( hasEmphasis() )
setBold(true);
}
if ( hasEmphasis() )
setColor (emphasis_color, getBackgroundColor());
else
setColor();
// Draw the text
if ( multiline && getHeight() >= 2 )
drawMultiLine();
else
drawSingleLine();
if ( isMonochron() )
{
setReverse(false);
if ( hasEmphasis() )
setBold(false);
}
}
//----------------------------------------------------------------------
void FLabel::drawMultiLine()
{
uInt y = 0;
uInt text_lines = uInt(multiline_text.size());
while ( y < text_lines && y < uInt(getHeight()) )
{
wchar_t* label_text;
bool hotkey_printed = false;
int align_offset, hotkeypos = -1;
uInt length = multiline_text[y].getLength();
try
{
label_text = new wchar_t[length + 1]();
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
wchar_t* src = const_cast<wchar_t*>(multiline_text[y].wc_str());
wchar_t* dest = const_cast<wchar_t*>(label_text);
if ( ! hotkey_printed )
hotkeypos = getHotkeyPos(src, dest, length);
else
std::wcsncpy(dest, src, length);
setPrintPos (1, 1 + int(y));
if ( hotkeypos != -1 )
{
align_offset = getAlignOffset (int(length - 1));
printLine (label_text, length - 1, hotkeypos, align_offset);
hotkey_printed = true;
hotkeypos = -1;
}
else
{
align_offset = getAlignOffset (int(length));
printLine (label_text, length, -1, align_offset);
}
y++;
delete[] label_text;
}
}
//----------------------------------------------------------------------
void FLabel::drawSingleLine()
{
wchar_t* label_text;
int hotkeypos = -1, align_offset;
uInt length = text.getLength();
try
{
label_text = new wchar_t[length + 1]();
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
hotkeypos = getHotkeyPos (text.wc_str(), label_text, length);
if ( hotkeypos != -1 )
length--;
setPrintPos (1,1);
align_offset = getAlignOffset (int(length));
printLine (label_text, length, hotkeypos, align_offset);
delete[] label_text;
}
//----------------------------------------------------------------------
void FLabel::printLine ( wchar_t line[]
, uInt length
@ -557,106 +668,3 @@ void FLabel::printLine ( wchar_t line[]
if ( hasReverseMode() )
setReverse(false);
}
//----------------------------------------------------------------------
void FLabel::draw()
{
wchar_t* label_text;
uInt length;
int hotkeypos, align_offset;
if ( isMonochron() )
{
setReverse(true);
if ( hasEmphasis() )
setBold(true);
}
if ( hasEmphasis() )
setColor (emphasis_color, getBackgroundColor());
else
setColor();
hotkeypos = -1;
if ( multiline && getHeight() >= 2 )
{
uInt y = 0;
uInt text_lines = uInt(multiline_text.size());
bool hotkey_printed = false;
while ( y < text_lines && y < uInt(getHeight()) )
{
length = multiline_text[y].getLength();
try
{
label_text = new wchar_t[length + 1]();
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
wchar_t* src = const_cast<wchar_t*>(multiline_text[y].wc_str());
wchar_t* dest = const_cast<wchar_t*>(label_text);
if ( ! hotkey_printed )
hotkeypos = getHotkeyPos(src, dest, length);
else
std::wcsncpy(dest, src, length);
setPrintPos (1, 1 + int(y));
if ( hotkeypos != -1 )
{
align_offset = getAlignOffset (int(length - 1));
printLine (label_text, length - 1, hotkeypos, align_offset);
hotkey_printed = true;
hotkeypos = -1;
}
else
{
align_offset = getAlignOffset (int(length));
printLine (label_text, length, -1, align_offset);
}
y++;
delete[] label_text;
}
}
else
{
length = text.getLength();
try
{
label_text = new wchar_t[length + 1]();
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
hotkeypos = getHotkeyPos (text.wc_str(), label_text, length);
if ( hotkeypos != -1 )
length--;
setPrintPos (1,1);
align_offset = getAlignOffset (int(length));
printLine (label_text, length, hotkeypos, align_offset);
delete[] label_text;
}
if ( isMonochron() )
{
setReverse(false);
if ( hasEmphasis() )
setBold(false);
}
}