Skip to content

Commit 115e14b

Browse files
committed
GTK+ GUI WIP
1 parent 0c55bcb commit 115e14b

File tree

3 files changed

+291
-5
lines changed

3 files changed

+291
-5
lines changed

ArduinoFloppyReader/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ bld/
2727
[Oo]bj/
2828
[Ll]og/
2929

30+
ArduinoReaderWriter
31+
GarduinoReaderWriter
32+
Garduino.glade
33+
*~
34+
3035
# Visual Studio 2015/2017 cache/options directory
3136
.vs/
3237
# Uncomment if you have tasks that create the project's static files in wwwroot
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
#include <gtkmm.h>
2+
#include <glibmm.h>
3+
#include <iostream>
4+
#include <thread>
5+
#include <string>
6+
#include <sigc++/sigc++.h>
7+
#include "../lib/ArduinoInterface.h"
8+
#include "../lib/ADFWriter.h"
9+
10+
class MainWindow : public Gtk::ApplicationWindow
11+
{
12+
public:
13+
MainWindow(BaseObjectType *obj, Glib::RefPtr<Gtk::Builder> const &builder)
14+
: Gtk::ApplicationWindow(obj), builder{builder}
15+
{
16+
std::vector<std::wstring> portList;
17+
ArduinoFloppyReader::ArduinoInterface::enumeratePorts(portList);
18+
Gtk::ComboBoxText *portsCombo = nullptr;
19+
builder->get_widget("serialPortsCombo", portsCombo);
20+
for (std::wstring port : portList)
21+
{
22+
const std::string portString(port.begin(), port.end());
23+
Glib::ustring text = Glib::ustring(portString.c_str(), port.size());
24+
portsCombo->append(text);
25+
}
26+
Gtk::Button *diagnosticsButton = nullptr;
27+
builder->get_widget("diagnosticsButton", diagnosticsButton);
28+
if (portList.size() > 0)
29+
{
30+
portsCombo->set_active(0);
31+
diagnosticsButton->set_sensitive(true);
32+
}
33+
diagnosticsButton->signal_clicked().connect([this, portsCombo]()
34+
{
35+
Glib::ustring serial = portsCombo->get_active_text();
36+
run_diagnostics(serial);
37+
});
38+
Gtk::Button *copyButton = nullptr;
39+
builder->get_widget("copyButton", copyButton);
40+
Gtk::Label *cylinderCount = nullptr;
41+
builder->get_widget("cylinderCount", cylinderCount);
42+
Gtk::Label *sideLabel = nullptr;
43+
builder->get_widget("sideLabel", sideLabel);
44+
Gtk::Label *goodCount = nullptr;
45+
builder->get_widget("goodCount", goodCount);
46+
Gtk::Label *partialCount = nullptr;
47+
builder->get_widget("partialCount", partialCount);
48+
49+
auto callback = [this, cylinderCount, sideLabel, goodCount, partialCount](const int currentTrack, const ArduinoFloppyReader::DiskSurface currentSide, const int retryCounter, const int sectorsFound, const int badSectorsFound) -> ArduinoFloppyReader::WriteResponse
50+
{
51+
std::string side = (currentSide == ArduinoFloppyReader::DiskSurface::dsUpper ? "Upper" : "Lower");
52+
std::cout << "currentTrack: " << currentTrack << " side: " << side << "retryCount: " << retryCounter << std::endl;
53+
cylinderCount->set_text(Glib::ustring::sprintf("%i", currentTrack));
54+
goodCount->set_text(Glib::ustring::sprintf("%i", sectorsFound));
55+
partialCount->set_text(Glib::ustring::sprintf("%i", badSectorsFound));
56+
sideLabel->set_text(side);
57+
while (gtk_events_pending())
58+
gtk_main_iteration();
59+
60+
if (retryCounter > 20)
61+
{
62+
// Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Aborted", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK);
63+
// dialog.run();
64+
// dialog.hide();
65+
66+
return ArduinoFloppyReader::WriteResponse::wrSkipBadChecksums;
67+
}
68+
69+
// Just continue
70+
return ArduinoFloppyReader::WriteResponse::wrContinue;
71+
};
72+
73+
Gtk::Entry *fileEntry = nullptr;
74+
builder->get_widget("fileNameEntry", fileEntry);
75+
Gtk::FileChooserButton *folderButton = nullptr;
76+
builder->get_widget("folderSelector", folderButton);
77+
Gtk::ComboBoxText *typeSelector = nullptr;
78+
builder->get_widget("typeSelector", typeSelector);
79+
fileEntry->signal_changed().connect([fileEntry, copyButton]()
80+
{
81+
if (fileEntry->get_text_length() > 0)
82+
{
83+
copyButton->set_sensitive(true);
84+
}
85+
else
86+
{
87+
copyButton->set_sensitive(false);
88+
}
89+
});
90+
Gtk::RadioButton *trackButton = nullptr;
91+
builder->get_widget("radio80", trackButton);
92+
copyButton->signal_clicked().connect([this, fileEntry, folderButton, typeSelector, trackButton, callback, portsCombo]()
93+
{
94+
Glib::ustring folder = folderButton->get_filename();
95+
Glib::ustring filename = folder + "/" + fileEntry->get_buffer()->get_text();
96+
ArduinoFloppyReader::ADFWriter writer;
97+
Glib::ustring serial = portsCombo->get_active_text();
98+
writer.openDevice(std::wstring(serial.begin(), serial.end()));
99+
bool tracks80 = trackButton->get_active();
100+
ArduinoFloppyReader::ADFResult readerResult;
101+
if (typeSelector->get_active_text() == "ADF")
102+
{
103+
readerResult = writer.DiskToADF(std::wstring(filename.begin(), filename.end()), tracks80 ? 80 : 82, callback);
104+
}
105+
else
106+
{
107+
readerResult = writer.DiskToSCP(std::wstring(filename.begin(), filename.end()), tracks80 ? 80 : 82, 3, callback);
108+
}
109+
// Handle the result
110+
handleResult(writer, readerResult);
111+
});
112+
}
113+
114+
virtual ~MainWindow() = default;
115+
116+
private
117+
:
118+
Glib::RefPtr<Gtk::Builder>
119+
builder;
120+
121+
void handleResult(ArduinoFloppyReader::ADFWriter writer, ArduinoFloppyReader::ADFResult readerResult)
122+
{
123+
switch (readerResult)
124+
{
125+
case ArduinoFloppyReader::ADFResult::adfrComplete:
126+
{
127+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Completed", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
128+
dialog.run();
129+
dialog.hide();
130+
break;
131+
}
132+
case ArduinoFloppyReader::ADFResult::adfrAborted:
133+
{
134+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Aborted", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
135+
dialog.run();
136+
dialog.hide();
137+
break;
138+
}
139+
case ArduinoFloppyReader::ADFResult::adfrFileError:
140+
{
141+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Unable to open the specified file to write to it.\nOutput File Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
142+
dialog.run();
143+
dialog.hide();
144+
break;
145+
}
146+
case ArduinoFloppyReader::ADFResult::adfrFileIOError:
147+
{
148+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "An error occured writing to the specified file.\nOutput File Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
149+
dialog.run();
150+
dialog.hide();
151+
break;
152+
}
153+
case ArduinoFloppyReader::ADFResult::adfrFirmwareTooOld:
154+
{
155+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "This requires firmware V1.8 or newer.\nFirmware out of date", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
156+
dialog.run();
157+
dialog.hide();
158+
break;
159+
}
160+
case ArduinoFloppyReader::ADFResult::adfrDiskWriteProtected:
161+
{
162+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "The disk is write protected", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
163+
dialog.run();
164+
dialog.hide();
165+
break;
166+
}
167+
case ArduinoFloppyReader::ADFResult::adfrCompletedWithErrors:
168+
{
169+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Completed with some errors", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
170+
dialog.run();
171+
dialog.hide();
172+
break;
173+
}
174+
case ArduinoFloppyReader::ADFResult::adfrDriveError:
175+
{
176+
std::string msg = "An error occured communicating with the Arduino interface:\r\n\r\n";
177+
msg += writer.getLastError();
178+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, msg.c_str(), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
179+
dialog.run();
180+
dialog.hide();
181+
break;
182+
}
183+
}
184+
}
185+
186+
bool showQuestion(bool isQuestion, const std::string question)
187+
{
188+
Gtk::ButtonsType buttons = Gtk::BUTTONS_OK_CANCEL;
189+
if (isQuestion)
190+
{
191+
buttons = Gtk::BUTTONS_YES_NO;
192+
}
193+
194+
Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, question, false, Gtk::MESSAGE_QUESTION, buttons);
195+
int Answer = dialog.run();
196+
dialog.hide();
197+
198+
// Process user choice
199+
bool isYes = false;
200+
switch (Answer)
201+
{
202+
case (Gtk::RESPONSE_OK):
203+
isYes = true;
204+
break;
205+
case (Gtk::RESPONSE_CANCEL):
206+
std::cout << "Cancel clicked." << std::endl;
207+
break;
208+
case (Gtk::RESPONSE_YES):
209+
std::cout << "Yes clicked." << std::endl;
210+
isYes = true;
211+
break;
212+
case (Gtk::RESPONSE_NO):
213+
std::cout << "No clicked." << std::endl;
214+
break;
215+
default:
216+
std::cout << "Unexpected button clicked." << std::endl;
217+
break;
218+
}
219+
return isYes;
220+
}
221+
222+
void showStatus(bool isError, std::string status)
223+
{
224+
std::string strLine;
225+
226+
if (isError)
227+
strLine = "DIAGNOSTICS FAILED: ";
228+
strLine += status.c_str();
229+
std::cerr << strLine << std::endl;
230+
Gtk::Statusbar *statusBar = nullptr;
231+
builder->get_widget("statusBar", statusBar);
232+
statusBar->pop();
233+
statusBar->push(strLine);
234+
}
235+
236+
void run_diagnostics(Glib::ustring serial)
237+
{
238+
ArduinoFloppyReader::ADFWriter writer;
239+
writer.runDiagnostics(
240+
std::wstring(serial.begin(), serial.end()), [this, serial](bool isError, const std::string message) -> void
241+
{
242+
while (gtk_events_pending())
243+
gtk_main_iteration();
244+
this->showStatus(isError, message);
245+
},
246+
[this, serial](bool isQuestion, const std::string question) -> bool
247+
{
248+
while (gtk_events_pending())
249+
gtk_main_iteration();
250+
return this->showQuestion(isQuestion, question);
251+
});
252+
}
253+
};
254+
255+
int main(int argc, char *argv[])
256+
{
257+
auto app = Gtk::Application::create(argc, argv, "be.sourcery.Garduino");
258+
auto builder = Gtk::Builder::create();
259+
260+
builder->add_from_file("Garduino.glade");
261+
262+
MainWindow *wnd = nullptr;
263+
264+
builder->get_widget_derived("MainWindow", wnd);
265+
266+
auto r = app->run(*wnd);
267+
268+
delete wnd;
269+
270+
return r;
271+
}

ArduinoFloppyReader/ArduinoFloppyReader/makefile

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
CC = g++
1010

1111
# define any compile-time flags
12-
CFLAGS = -Wall -std=c++14 -Wno-psabi -O3
12+
CFLAGS = -Wall -std=c++14 -Wno-psabi -O0
13+
GCFLAGS = ${CFLAGS} $(shell pkg-config --cflags gtkmm-3.0)
1314

1415
# define any directories containing header files other than /usr/include
1516
#
@@ -19,15 +20,17 @@ INCLUDES = -I../lib
1920
# if I wanted to include libraries not in /usr/lib I'd specify
2021
# their path using -Lpath, something like:
2122
LFLAGS = -L../lib
23+
GLFLAGS = ${LFLAGS} $(shell pkg-config --libs gtkmm-3.0)
2224

2325
# define any libraries to link into executable:
2426
# if I want to link in libraries (libx.so or libx.a) I use the -llibname
2527
# option, something like (this will link in libmylib.so and libm.so:
2628
LIBS =
2729

28-
# define the C source files
29-
SRCS = Main.cpp ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoInterface.cpp ../lib/ADFWriter.cpp
30-
30+
# define the C surce files
31+
COMMON_SRC = ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoInterface.cpp ../lib/ADFWriter.cpp
32+
SRCS = Main.cpp ${COMMON_SRC}
33+
GSRCS = GarduinoReaderWriter.cpp ${COMMON_SRC}
3134
# define the C object files
3235
#
3336
# This uses Suffix Replacement within a macro:
@@ -37,10 +40,14 @@ SRCS = Main.cpp ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoI
3740
# with the .o suffix
3841
#
3942
OBJS = $(SRCS:.c=.o)
43+
GOBJS = $(GSRCS:.c=.o)
4044

4145
# define the executable file
4246
MAIN = ArduinoReaderWriter
4347

48+
#GUI
49+
GARDUINO = GarduinoReaderWriter
50+
4451
#
4552
# The following part of the makefile is generic; it can be used to
4653
# build any executable just by changing the definitions above and by
@@ -55,6 +62,9 @@ all: $(MAIN)
5562
$(MAIN): $(OBJS)
5663
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
5764

65+
$(GARDUINO): $(GOBJS) makefile Garduino.glade
66+
$(CC) $(GCFLAGS) $(INCLUDES) -o $(GARDUINO) $(GOBJS) $(GLFLAGS) $(LIBS)
67+
5868
# this is a suffix replacement rule for building .o's from .c's
5969
# it uses automatic variables $<: the name of the prerequisite of
6070
# the rule(a .c file) and $@: the name of the target of the rule (a .o file)
@@ -63,7 +73,7 @@ $(MAIN): $(OBJS)
6373
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
6474

6575
clean:
66-
$(RM) *.o *~ $(MAIN)
76+
$(RM) *.o *~ $(MAIN) ${GARDUINO}
6777

6878
depend: $(SRCS)
6979
makedepend $(INCLUDES) $^

0 commit comments

Comments
 (0)