Simple Text Editor - Complete
Documentation
Table of Contents
1. Project Overview
2. Features
3. Architecture
4. Implementation Details
5. User Interface
6. File Management
7. Search and Replace
8. Themes and Appearance
9. Auto-Save System
10.Recent Files Management
11.Status Bar
12.Keyboard Shortcuts
13.Build Instructions
14.Code Structure
15.Error Handling
16.Future Enhancements
Project Overview
The Simple Text Editor is a cross-platform desktop text editor built using the FLTK (Fast Light
Toolkit) GUI library and C++. It provides essential text editing capabilities with a clean,
intuitive interface suitable for basic to intermediate text editing tasks.
Technology Stack
● Programming Language: C++11
● GUI Framework: FLTK 1.3+
● Build System: Standard C++ compiler (g++/clang++/MSVC)
● Platforms: Windows, Linux, macOS
Design Goals
● Lightweight and fast performance
● Simple, intuitive user interface
● Essential text editing features
● Cross-platform compatibility
● Minimal dependencies
Features
Core Text Editing
✅ New Document Creation
✅ File Opening and Saving
✅ Cut, Copy, Paste Operations
✅ Undo/Redo Support (via FLTK built-in)
✅ Find and Replace Functionality
✅ Multi-line Text Editing
Advanced Features
✅ Recent Files Management
✅ Auto-Save System
✅ Dark Mode Theme
✅ Fullscreen Mode
✅ Status Bar with Document Information
✅ Modal Dialogs for Search Operations
✅ Keyboard Shortcuts Support
User Experience
✅ Intuitive Menu System
✅ File Change Detection
✅ Unsaved Changes Warning
✅ Error Message Handling
✅ Responsive Interface
Architecture
Component Diagram
┌─────────────────────────────────────────┐
│ Main Window │
├─────────────────────────────────────────┤
│ Menu Bar (File, Edit, View, Help) │
├─────────────────────────────────────────┤
│ │
│ Text Editor Widget │
│ (Fl_Text_Editor) │
│ │
├─────────────────────────────────────────┤
│ Status Bar (File info, Cursor pos) │
└─────────────────────────────────────────┘
┌─────────────────┐ ┌─────────────────┐
│ Find Dialog │ │ Replace Dialog │
│ (Modal) │ │ (Modal) │
└─────────────────┘ └─────────────────┘
Class Structure
EditorWindow : Fl_Double_Window
├── Fl_Text_Editor *editor
├── Fl_Window *find_dlg
├── Fl_Window *replace_dlg
├── Fl_Input *find_input
├── Fl_Input *replace_find
├── Fl_Input *replace_with
└── char search[256]
Implementation Details
1. Window Management
EditorWindow Class
struct EditorWindow : public Fl_Double_Window
{
Fl_Text_Editor *editor; // Main text editing widget
Fl_Window *find_dlg; // Find dialog window
Fl_Window *replace_dlg; // Replace dialog window
Fl_Input *find_input; // Find input field
Fl_Input *replace_find; // Replace find field
Fl_Input *replace_with; // Replace with field
char search[256]; // Current search string
};
Key Implementation Points:
● Inherits from Fl_Double_Window for better rendering performance
● Manages dialog windows as members for proper cleanup
● Stores search state to maintain user experience
● Custom destructor ensures proper resource cleanup
2. Text Buffer Management
Text Buffer Implementation
Fl_Text_Buffer *textbuf = nullptr; // Global text buffer
// Initialization
textbuf = new Fl_Text_Buffer;
editor->buffer(textbuf);
textbuf->add_modify_callback(changed_cb, main_win);
Features:
● Single global text buffer shared across the application
● Modify callback system for change detection
● Automatic memory management
● Support for large files
3. Change Detection System
Implementation
void changed_cb(int, int nInserted, int nDeleted, int, const char *, void *)
{
if ((nInserted || nDeleted) && !loading) {
changed = 1;
set_title(main_win);
update_status();
}
}
Functionality:
● Detects text insertions and deletions
● Ignores changes during file loading operations
● Updates window title and status bar immediately
● Prevents unnecessary updates during batch operations
User Interface
Menu System Architecture
Menu Structure
Fl_Menu_Item menuitems[] = {
{"&File", 0, 0, 0, FL_SUBMENU},
{"&New", FL_CTRL + 'n', new_cb},
{"&Open...", FL_CTRL + 'o', open_cb},
{"&Save", FL_CTRL + 's', save_cb},
{"Save &As...", FL_CTRL + FL_SHIFT + 's', saveas_cb},
{"&Quit", FL_CTRL + 'q', quit_cb},
{"&Edit", 0, 0, 0, FL_SUBMENU},
{"Cu&t", FL_CTRL + 'x', cut_cb},
{"&Copy", FL_CTRL + 'c', copy_cb},
{"&Paste", FL_CTRL + 'v', paste_cb},
{"&Find...", FL_CTRL + 'f', find_cb},
{"&Replace...", FL_CTRL + 'r', replace_cb},
{"&View", 0, 0, 0, FL_SUBMENU},
{"&Fullscreen", FL_F + 11, toggle_fullscreen_cb},
{"&Dark Mode", FL_CTRL + 'd', toggle_darkmode_cb},
{"&Help", 0, 0, 0, FL_SUBMENU},
{"&About", 0, about_cb}
};
Design Principles:
● Standard menu organization following platform conventions
● Keyboard shortcuts for common operations
● Mnemonic keys for accessibility (& prefix)
● Logical grouping of related functions
Layout Management
Window Layout
// Main window: 1000x700 pixels
main_win = new EditorWindow(1000, 700, "Simple Editor");
// Components:
// Menu Bar: 0, 0, 1000, 25 (top strip)
// Text Editor: 0, 25, 1000, 650 (main area)
// Status Bar: 0, 675, 1000, 25 (bottom strip)
Responsive Design:
● Text editor is set as resizable widget
● Status bar and menu bar maintain fixed heights
● Window can be resized maintaining proper proportions
File Management
File Operations Implementation
Open File Function
void open_cb(Fl_Widget *, void *)
{
if (!check_save()) return; // Check for unsaved changes
const char *newfile = fl_file_chooser("Open File", "*", filename);
if (newfile) {
loading = 1; // Prevent change callbacks
if (textbuf->loadfile(newfile) == 0) { // Load file
strcpy(filename, newfile); // Update filename
changed = 0; // Mark as unchanged
add_recent(newfile); // Add to recent files
} else {
fl_alert("Error reading from file '%s':\n%s.",
newfile, strerror(errno)); // Error handling
}
loading = 0; // Re-enable callbacks
set_title(main_win); // Update title
update_status(); // Update status bar
}
}
Key Features:
● Unsaved changes protection
● Error handling with user feedback
● Recent files integration
● Status updates
● Loading flag to prevent spurious change detection
Save File Function
void save_cb(Fl_Widget *, void *)
{
if (filename[0] == '\0') { // No filename set
saveas_cb(nullptr, nullptr); // Trigger Save As
return;
}
if (textbuf->savefile(filename) == 0) { // Save successful
changed = 0; // Mark as saved
add_recent(filename); // Update recent files
set_title(main_win); // Update title
update_status(); // Update status
} else {
fl_alert("Error writing to file '%s':\n%s.",
filename, strerror(errno)); // Error feedback
}
}
Unsaved Changes Protection
Implementation
int check_save()
{
if (!changed) return 1; // No changes, continue
int r = fl_choice("The current file has not been saved.\n"
"Would you like to save it now?",
"Cancel", "Save", "Don't Save");
if (r == 1) { // User chose Save
save_cb(nullptr, nullptr);
return !changed; // Return success status
}
return (r == 2) ? 1 : 0; // Don't Save = 1, Cancel = 0
}
User Experience:
● Three-button choice dialog
● Clear action descriptions
● Respects user's decision
● Prevents data loss
Search and Replace
Find Dialog Implementation
Dialog Creation
void find_cb(Fl_Widget *, void *)
{
EditorWindow *ew = static_cast<EditorWindow*>(main_win);
if (!ew->find_dlg) { // Create dialog if needed
ew->find_dlg = new Fl_Window(350, 100, "Find");
ew->find_dlg->begin();
new Fl_Box(10, 10, 60, 25, "Find:"); // Label
ew->find_input = new Fl_Input(70, 10, 200, 25); // Input field
ew->find_input->value(ew->search); // Restore previous search
Fl_Button *find_btn = new Fl_Button(280, 10, 60, 25, "Find");
find_btn->callback(find_ok_cb); // Set callback
Fl_Button *cancel_btn = new Fl_Button(280, 45, 60, 25, "Cancel");
cancel_btn->callback(find_cancel_cb); // Cancel callback
ew->find_dlg->end();
ew->find_dlg->set_modal(); // Make dialog modal
}
ew->find_dlg->show(); // Display dialog
}
Search Algorithm
Forward Search Implementation
void find_next(const char *search_str)
{
if (!search_str || !search_str[0]) return;
EditorWindow *ew = static_cast<EditorWindow*>(main_win);
int pos = ew->editor->insert_position(); // Current cursor position
int found_pos;
if (textbuf->search_forward(pos, search_str, &found_pos)) {
textbuf->select(found_pos, found_pos + strlen(search_str));
ew->editor->insert_position(found_pos + strlen(search_str));
ew->editor->show_insert_position(); // Scroll to result
} else {
fl_alert("No more occurrences of '%s' found!", search_str);
}
}
Replace Functionality
Single Replace
void replace_ok_cb(Fl_Widget *, void *)
{
// Get search and replace strings
const char *find_str = ew->replace_find->value();
const char *replace_str = ew->replace_with->value();
// Perform search
if (textbuf->search_forward(pos, find_str, &found_pos)) {
textbuf->select(found_pos, found_pos + strlen(find_str));
textbuf->remove_selection(); // Remove found text
textbuf->insert(found_pos, replace_str); // Insert replacement
// Update cursor position and mark as changed
}
}
Replace All
void replace_all_cb(Fl_Widget *, void *)
{
int count = 0;
int pos = 0;
int found_pos;
// Loop through all occurrences
while (textbuf->search_forward(pos, find_str, &found_pos)) {
textbuf->select(found_pos, found_pos + strlen(find_str));
textbuf->remove_selection();
textbuf->insert(found_pos, replace_str);
pos = found_pos + strlen(replace_str); // Update position
count++;
}
fl_message("Replaced %d occurrences.", count); // User feedback
}
Themes and Appearance
Dark Mode Implementation
Color Scheme Management
void toggle_darkmode_cb(Fl_Widget *, void *)
{
dark_mode = !dark_mode;
EditorWindow *ew = static_cast<EditorWindow*>(main_win);
if (dark_mode) {
// Dark mode colors
ew->editor->color(fl_rgb_color(40, 40, 40)); // Dark background
ew->editor->textcolor(FL_WHITE); // White text
ew->editor->cursor_color(FL_WHITE); // White cursor
ew->editor->selection_color(fl_rgb_color(70, 70, 70)); // Dark selection
status_bar->color(fl_rgb_color(30, 30, 30)); // Dark status bar
status_bar->labelcolor(FL_WHITE); // White status text
main_win->color(fl_rgb_color(30, 30, 30)); // Dark window
} else {
// Light mode colors (standard)
ew->editor->color(FL_WHITE);
ew->editor->textcolor(FL_BLACK);
ew->editor->cursor_color(FL_BLACK);
ew->editor->selection_color(fl_rgb_color(200, 200, 255));
status_bar->color(FL_WHITE);
status_bar->labelcolor(FL_BLACK);
main_win->color(FL_WHITE);
}
main_win->redraw(); // Force redraw
}
Font Configuration
ew->editor->textfont(FL_COURIER); // Monospace font
ew->editor->textsize(14); // 14pt font size
Fullscreen Mode
Implementation
void toggle_fullscreen_cb(Fl_Widget *, void *)
{
if (!is_fullscreen) {
main_win->fullscreen(); // Enter fullscreen
} else {
main_win->fullscreen_off(); // Exit fullscreen
}
is_fullscreen = !is_fullscreen; // Toggle state
}
Auto-Save System
Timer-Based Auto-Save
Implementation
const double AUTOSAVE_INTERVAL = 60.0; // 60 seconds
void schedule_autosave(void *)
{
if (changed && filename[0]) { // Only if file has name and changes
char autosave_name[512];
snprintf(autosave_name, sizeof(autosave_name),
"%[Link]", filename); // Create backup filename
textbuf->savefile(autosave_name); // Save backup
}
Fl::repeat_timeout(AUTOSAVE_INTERVAL, schedule_autosave); // Schedule next
}
Features:
● Automatic backup every 60 seconds
● Only creates backups for named files with changes
● Uses .autosave extension for backup files
● Non-intrusive background operation
● Uses FLTK's timer system for reliability
Auto-Save File Management
Backup File Naming
● Original file: [Link]
● Backup file: [Link]
● Easy to identify and recover
● Doesn't interfere with normal file operations
Recent Files Management
Persistent Storage
File Format
const char *RECENT_FILENAME = "[Link]";
The recent files are stored in a simple text file format:
/path/to/[Link]
/path/to/[Link]
/path/to/[Link]
Loading Recent Files
void load_recent()
{
std::ifstream in(RECENT_FILENAME);
std::string line;
recent_files.clear(); // Clear existing list
while (recent_files.size() < 5 && std::getline(in, line)) {
if (![Link]()) { // Skip empty lines
recent_files.push_back(line); // Add to vector
}
}
}
Saving Recent Files
void save_recent()
{
std::ofstream out(RECENT_FILENAME);
for (const auto &f : recent_files) {
out << f << "\n"; // Write each file path
}
}
Dynamic Menu Updates
Adding Recent Files to Menu
void add_recent(const char *f)
{
if (!f || !f[0]) return; // Validate input
// Remove if already exists (avoid duplicates)
recent_files.erase(std::remove(recent_files.begin(),
recent_files.end(), f), recent_files.end());
recent_files.insert(recent_files.begin(), f); // Add to front
if (recent_files.size() > 5) { // Limit to 5 files
recent_files.resize(5);
}
save_recent(); // Persist changes
}
Menu Integration
// Add recent files to menu dynamically
for (size_t i = 0; i < recent_files.size() && i < 5; ++i) {
char label[512];
snprintf(label, sizeof(label), "File/Recent Files/%s",
recent_files[i].c_str());
menubar->add(label, 0, open_recent_cb,
(void*)recent_files[i].c_str());
}
Status Bar
Information Display
Status Bar Implementation
void update_status()
{
if (!status_bar || !main_win || !textbuf) return;
EditorWindow *ew = static_cast<EditorWindow*>(main_win);
int pos = ew->editor->insert_position(); // Cursor position
// Calculate line and column numbers
int line = 1;
int col = 1;
const char *text = textbuf->text();
for (int i = 0; i < pos && text[i]; i++) {
if (text[i] == '\n') {
line++; // New line found
col = 1; // Reset column
} else {
col++; // Increment column
}
}
free((void*)text); // Free text buffer
// Format status string
char buf[512];
snprintf(buf, sizeof(buf), "File: %s | Line: %d, Col: %d | Length: %d",
filename[0] ? filename : "Untitled", line, col, textbuf->length());
status_bar->copy_label(buf); // Update display
}
Status Information
The status bar displays:
1. Current filename (or "Untitled" for new files)
2. Cursor line number (1-based)
3. Cursor column number (1-based)
4. Total document length in characters
Update Triggers:
● Text modifications
● Cursor movement
● File operations
● Window focus changes
Keyboard Shortcuts
Standard Shortcuts
Function Shortcut Description
New File Ctrl+N Create new document
Open File Ctrl+O Open existing file
Save File Ctrl+S Save current file
Save As Ctrl+Shift Save with new name
+S
Quit Ctrl+Q Exit application
Cut Ctrl+X Cut selected text
Copy Ctrl+C Copy selected text
Paste Ctrl+V Paste clipboard
content
Find Ctrl+F Open find dialog
Replace Ctrl+R Open replace dialog
Fullscreen F11 Toggle fullscreen mode
Dark Mode Ctrl+D Toggle dark theme
FLTK Built-in Shortcuts
The text editor widget provides additional built-in shortcuts:
● Ctrl+A - Select All
● Ctrl+Z - Undo
● Ctrl+Y - Redo
● Home/End - Line navigation
● Ctrl+Home/End - Document navigation
● Shift+Arrow Keys - Text selection
Build Instructions
Prerequisites
Linux (Ubuntu/Debian)
sudo apt-get update
sudo apt-get install build-essential
sudo apt-get install libfltk1.3-dev
macOS
# Using Homebrew
brew install fltk
Windows
● Install FLTK from official website
● Use MinGW or Visual Studio
Compilation
Basic Compilation
g++ -std=c++11 simple_editor.cpp -lfltk -o simple_editor
With Optimization
g++ -std=c++11 -O2 simple_editor.cpp -lfltk -o simple_editor
Debug Build
g++ -std=c++11 -g -DDEBUG simple_editor.cpp -lfltk -o simple_editor
Platform-Specific Notes
Linux:
● May need additional libraries: -lfltk_images -lfltk_gl
● For static linking: -static-libgcc -static-libstdc++
macOS:
● May need framework flags: -framework Cocoa
● Universal binary: -arch x86_64 -arch arm64
Windows:
● Link with: -lfltk -lole32 -luuid -lcomctl32
● For console output: -mconsole
Code Structure
File Organization
simple_editor.cpp
├── Headers and Includes
├── Global Variables
├── Forward Declarations
├── EditorWindow Class Definition
├── Callback Implementations
│ ├── File Operations
│ ├── Edit Operations
│ ├── Search/Replace Operations
│ ├── View Operations
│ └── Utility Functions
├── Menu Definition
└── Main Function
Function Categories
File Operations
● new_cb() - Create new file
● open_cb() - Open existing file
● save_cb() - Save current file
● saveas_cb() - Save with new name
● quit_cb() - Exit application
Edit Operations
● copy_cb() - Copy selected text
● cut_cb() - Cut selected text
● paste_cb() - Paste clipboard content
Search Operations
● find_cb() - Open find dialog
● find_next() - Find next occurrence
● replace_cb() - Open replace dialog
● replace_ok_cb() - Replace current
● replace_all_cb() - Replace all occurrences
View Operations
● toggle_fullscreen_cb() - Toggle fullscreen
● toggle_darkmode_cb() - Toggle dark theme
Utility Functions
● set_title() - Update window title
● update_status() - Update status bar
● check_save() - Check for unsaved changes
● changed_cb() - Handle text modifications
Memory Management
Resource Allocation
● Text buffer created once, reused for document lifetime
● Dialog windows created on demand, cached for reuse
● Menu items allocated statically
● Recent files stored in STL container
Cleanup Strategy
● EditorWindow destructor handles dialog cleanup
● FLTK handles widget cleanup automatically
● Text buffer freed by FLTK on application exit
● Recent files saved on each update
Error Handling
File Operation Errors
Error Types Handled
● File not found
● Permission denied
● Disk full
● Network errors (for network drives)
● Invalid file format
User Feedback
fl_alert("Error reading from file '%s':\n%s.", filename, strerror(errno));
Error Recovery
● Operations fail gracefully
● Application state remains consistent
● User can retry or choose different action
● No data loss on error conditions
Input Validation
Search String Validation
if (!search_str || !search_str[0]) return; // Empty string check
File Path Validation
if (!f || !f[0]) return; // Null/empty path check
Widget State Validation
if (!ew || !ew->editor) return; // Widget existence check
Robust Operation Design
Defensive Programming
● Null pointer checks before dereferencing
● Bounds checking for array access
● State validation before operations
● Graceful degradation on errors
Future Enhancements
Planned Features
Text Processing
● [ ] Syntax highlighting
● [ ] Line numbering
● [ ] Code folding
● [ ] Auto-indentation
● [ ] Tab/space conversion
File Management
● [ ] Multiple document tabs
● [ ] Session management
● [ ] Project file support
● [ ] File browser integration
● [ ] Backup file recovery
Search Enhancement
● [ ] Regular expression support
● [ ] Case-insensitive search
● [ ] Whole word matching
● [ ] Search history
● [ ] Find in files
User Interface
● [ ] Configurable themes
● [ ] Customizable shortcuts
● [ ] Tool bar
● [ ] Split view
● [ ] Minimap
Advanced Features
● [ ] Plugin system
● [ ] Macro recording
● [ ] Spell checking
● [ ] Print support
● [ ] Export options
Architecture Improvements
Code Organization
● Separate header files
● Class-based design
● Configuration management
● Plugin architecture
Performance Optimization
● Lazy loading for large files
● Incremental search
● Background operations
● Memory pool allocation
Platform Integration
● Native file dialogs
● System theme integration
● Desktop notifications
● File association
Conclusion
The Simple Text Editor demonstrates a well-structured approach to GUI application
development using FLTK and C++. It provides essential text editing functionality while
maintaining code clarity and extensibility. The modular design allows for easy enhancement
and customization, making it suitable as both a standalone application and a foundation for
more complex text editing tools.
The implementation showcases best practices in:
● Event-driven programming
● Resource management
● User interface design
● Error handling
● Cross-platform development
This documentation serves as both a user guide and a developer reference, providing
comprehensive information about the application's features, architecture, and
implementation details.