4 Website: http://www.vultaire.net/software/jben/
5 License: GNU General Public License (GPL) version 2
6 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
8 File: panel_kanjidrill.cpp
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>
24 #include "panel_kanjidrill.h"
32 /* Controls to configure the test */
42 /* Controls for use during the test */
59 BEGIN_EVENT_TABLE(PanelKanjiDrill
, wxPanel
)
60 EVT_SPINCTRL(ID_spnKanjiCount
, PanelKanjiDrill::OnKanjiCountChange
)
61 EVT_RADIOBUTTON(ID_rdoRandom
, PanelKanjiDrill::OnRdoRandom
)
62 EVT_RADIOBUTTON(ID_rdoStartIndex
, PanelKanjiDrill::OnRdoStartIndex
)
63 EVT_BUTTON(ID_btnStart
, PanelKanjiDrill::OnStart
)
65 EVT_BUTTON(ID_btnCorrect
, PanelKanjiDrill::OnCorrect
)
66 EVT_BUTTON(ID_btnWrong
, PanelKanjiDrill::OnWrong
)
67 EVT_BUTTON(ID_btnStop
, PanelKanjiDrill::OnStop
)
74 PanelKanjiDrill::PanelKanjiDrill(wxWindow
*owner
) : RedrawablePanel(owner
) {
75 /* Create test config controls */
76 pnlConfig
= new wxPanel(this, ID_pnlConfig
);
78 wxPanel
*pnlKanjiSelect
= new wxPanel(pnlConfig
, wxID_ANY
);
79 wxStaticText
*lblKanjiCount
= new wxStaticText(pnlKanjiSelect
, wxID_ANY
, _T("Number of kanji to test: "));
80 spnKanjiCount
= new wxSpinCtrl(pnlKanjiSelect
, ID_spnKanjiCount
);
81 spnKanjiCount
->SetValue(20);
82 rdoRandom
= new wxRadioButton(pnlKanjiSelect
, ID_rdoRandom
, _T("Choose randomly from list"), wxDefaultPosition
, wxDefaultSize
, wxRB_GROUP
);
83 rdoStartIndex
= new wxRadioButton(pnlKanjiSelect
, ID_rdoStartIndex
, _T("Start at index: "));
84 spnStartIndex
= new wxSpinCtrl(pnlKanjiSelect
, ID_spnStartIndex
);
85 spnStartIndex
->Enable(false);
87 wxPanel
*pnlTestSelect
= new wxPanel(pnlConfig
, wxID_ANY
);
88 rdoKanjiReading
= new wxRadioButton(pnlTestSelect
, ID_rdoKanjiReading
, _T("Reading Kanji"), wxDefaultPosition
, wxDefaultSize
, wxRB_GROUP
);
89 rdoKanjiWriting
= new wxRadioButton(pnlTestSelect
, ID_rdoKanjiWriting
, _T("Writing Kanji"));
91 btnStart
= new wxButton(pnlConfig
, ID_btnStart
, _T("Start Drill"));
93 /* Create test controls */
94 pnlTest
= new wxPanel(this, ID_pnlTest
);
95 txtKanji
= new CoveredTextBox(pnlTest
, ID_txtKanji
, _T("< Kanji >"));
96 wxFont fnt
= txtKanji
->GetFont();
97 fnt
.SetPointSize(fnt
.GetPointSize()+10);
98 txtKanji
->SetFont(fnt
);
99 txtOnyomi
= new CoveredTextBox(pnlTest
, ID_txtOnyomi
, _T("< Onyomi >"));
100 txtKunyomi
= new CoveredTextBox(pnlTest
, ID_txtKunyomi
, _T("< Kunyomi >"));
101 txtEnglish
= new CoveredTextBox(pnlTest
, ID_txtEnglish
, _T("< English >"), _T("Some overly ridiculously long English string to see how resizing will work when uncovering a string which is too big for the current shape/size of the CoveredTextBox."));
102 btnCorrect
= new wxButton(pnlTest
, ID_btnCorrect
, _T("Correct"));
103 btnWrong
= new wxButton(pnlTest
, ID_btnWrong
, _T("Wrong"));
104 btnStop
= new wxButton(pnlTest
, ID_btnStop
, _T("Stop Drill"));
105 lblTestProgress
= new wxStaticText(pnlTest
, ID_lblTestProgress
, _T(""));
108 /* Our custom radio box for selecting the kanji to test */
109 wxStaticBoxSizer
*kanjiConfigSizer
= new wxStaticBoxSizer(wxVERTICAL
, pnlKanjiSelect
, _T("Choose Kanji to Test"));
110 /* Row 1: Number of kanji to test */
111 wxBoxSizer
*kanjiCountSizer
= new wxBoxSizer(wxHORIZONTAL
);
112 kanjiCountSizer
->Add(lblKanjiCount
, 0, wxALIGN_CENTER_VERTICAL
);
113 kanjiCountSizer
->Add(spnKanjiCount
, 0, wxALIGN_CENTER_VERTICAL
);
114 /* Row 2: Random kanji, or do range by start index */
115 wxBoxSizer
*kanjiSelectSizer
= new wxBoxSizer(wxVERTICAL
);
116 kanjiSelectSizer
->Add(rdoRandom
, 1, wxALIGN_CENTER_VERTICAL
);
117 wxBoxSizer
*kanjiStartIndexSizer
= new wxBoxSizer(wxHORIZONTAL
);
118 kanjiStartIndexSizer
->Add(rdoStartIndex
, 0, wxALIGN_CENTER_VERTICAL
);
119 kanjiStartIndexSizer
->Add(spnStartIndex
, 0, wxALIGN_CENTER_VERTICAL
);
120 kanjiStartIndexSizer
->AddStretchSpacer(1);
121 kanjiSelectSizer
->Add(kanjiStartIndexSizer
, 1, wxEXPAND
| wxALIGN_CENTER_VERTICAL
);
122 /* Finally: Add both rows to the static box sizer */
123 kanjiConfigSizer
->Add(kanjiCountSizer
, 0);
124 kanjiConfigSizer
->Add(kanjiSelectSizer
, 0, wxEXPAND
);
125 pnlKanjiSelect
->SetSizer(kanjiConfigSizer
);
127 /* Our custom radio box for selecting the test mode */
128 wxStaticBoxSizer
*testModeSizer
= new wxStaticBoxSizer(wxVERTICAL
, pnlTestSelect
, _T("Choose Test Type"));
129 testModeSizer
->Add(rdoKanjiReading
, 1);
130 testModeSizer
->Add(rdoKanjiWriting
, 1);
131 pnlTestSelect
->SetSizer(testModeSizer
);
133 /* Create any other horizontal sizers */
134 wxBoxSizer
*correctWrongSizer
= new wxBoxSizer(wxHORIZONTAL
);
135 correctWrongSizer
->Add(btnCorrect
, 0, wxRIGHT
, 10);
136 correctWrongSizer
->Add(btnWrong
);
137 correctWrongSizer
->AddStretchSpacer(1);
138 correctWrongSizer
->Add(btnStop
);
139 /* The config sizer */
140 wxBoxSizer
*configSizer
= new wxBoxSizer(wxVERTICAL
);
141 configSizer
->Add(pnlKanjiSelect
, 0, wxEXPAND
| wxBOTTOM
, 10);
142 configSizer
->Add(pnlTestSelect
, 0, wxEXPAND
| wxBOTTOM
, 10);
143 configSizer
->Add(btnStart
, 0, wxALIGN_CENTER_HORIZONTAL
);
144 pnlConfig
->SetSizer(configSizer
);
145 /* The test mode sizer */
146 wxBoxSizer
*testSizer
= new wxBoxSizer(wxVERTICAL
);
147 testSizer
->Add(txtKanji
, 0, wxEXPAND
| wxBOTTOM
, 10);
148 testSizer
->Add(txtOnyomi
, 0, wxEXPAND
| wxBOTTOM
, 10);
149 testSizer
->Add(txtKunyomi
, 0, wxEXPAND
| wxBOTTOM
, 10);
150 testSizer
->Add(txtEnglish
, 0, wxEXPAND
| wxBOTTOM
, 10);
151 testSizer
->Add(correctWrongSizer
, 0, wxEXPAND
);
152 testSizer
->AddStretchSpacer(1);
153 testSizer
->Add(lblTestProgress
, 0, wxEXPAND
);
154 pnlTest
->SetSizer(testSizer
);
155 /* The panel-wide sizer */
156 wxBoxSizer
*panelSizer
= new wxBoxSizer(wxVERTICAL
);
157 panelSizer
->Add(pnlConfig
, 1, wxEXPAND
| wxALL
, 10);
158 panelSizer
->Add(pnlTest
, 1, wxEXPAND
| wxALL
, 10);
161 pnlTest
->Show(false); /* Set the test panel as invisible at the beginning */
162 this->SetSizerAndFit(panelSizer
); /* Now apply the sizer afterwards so layout occurs properly. */
165 void PanelKanjiDrill::OnStart(wxCommandEvent
& ev
) {
166 /* Placeholder code */
167 /* We need to do the following:
168 0. (Possibly) Verify that test mode is NOT enabled when this event is triggered
169 (In case the button can somehow be pushed when not visible.) (Done)
170 0.5. (Possibly) Validate the input of the user. Might not be necessary if all controls limit input properly.
172 1. Reset any test variables
173 2. Create kanji test list based upon selected options
174 3. Load up the first kanji to be tested
175 4. Switch to the test GUI */
177 unsigned int i
, startIndex
;
179 /* Reset test variables */
180 currentKanjiIndex
= -1;
181 extraPractice
= false;
182 lastWasCorrect
= false; /* used for Extra Practice mode only */
183 totalToTest
= spnKanjiCount
->GetValue();
186 correct
= totalTested
= 0;
187 if(rdoKanjiReading
->GetValue()) testMode
= PKD_TM_Reading
;
188 else if(rdoKanjiWriting
->GetValue()) testMode
= PKD_TM_Writing
;
190 wxMessageBox(_T("Unknown test mode selected!"), _T("Error!"), wxOK
| wxICON_ERROR
, this);
194 /* Create kanji test list based upon selected options */
195 if(rdoStartIndex
->GetValue()) {
196 /* Copy from study list at specified index */
197 startIndex
= spnStartIndex
->GetValue() - 1; /* Remember, the GUI uses a 1-base. */
198 for(i
=startIndex
; i
< startIndex
+ totalToTest
; i
++)
199 testKanji
.push_back((*jben
->kanjiList
)[i
]);
201 /* Random character selection */
202 vector
<wxChar
> localVector
= jben
->kanjiList
->GetVector();
204 while(testKanji
.size()<totalToTest
) {
205 i
= rand() % localVector
.size();
207 testKanji
.push_back(c
);
208 localVector
.erase(localVector
.begin() + i
);
212 /* Debug: Show our list of kanji to test */
214 printf("DEBUG: Kanji to test: ");
215 for(vector
<wxChar
>::iterator vi
=testKanji
.begin();vi
!=testKanji
.end();vi
++)
220 /* Load up the first kanji */
223 /* Switch the displayed panel */
224 jben
->gui
->GetMenuBar()->EnableTop(GUI_menuKanji
, false);
225 pnlConfig
->Show(false);
228 this->GetSizer()->Layout();
233 void PanelKanjiDrill::Stop() {
235 if(totalTested
>0) score
= round(100000*
237 (double)totalTested
)/1000;
238 wxString kanjiMissed
;
239 for(vector
<wxChar
>::iterator vi
=missedKanji
.begin(); vi
!=missedKanji
.end(); vi
++)
240 kanjiMissed
.append(*vi
);
242 /* Display test results */
243 if(totalTested
==totalToTest
) {
245 wxString::Format(_T("TEST COMPLETED\n\nFinal Score: %d/%d (%0.3f%%)\nKanji Missed: %s"),
246 correct
, totalTested
, score
, kanjiMissed
.c_str()),
247 _T("Test Results"), wxOK
| wxICON_INFORMATION
, this);
250 wxString::Format(_T("TEST INCOMPLETE\n\nScore: %d/%d (%0.3f%%)\nTest Progress: %d/%d (%0.3f%%)\nKanji Missed: %s"),
251 correct
, totalTested
, score
, totalTested
, totalToTest
,
252 round(100000*(double)totalTested
/(double)totalToTest
)/1000,
253 kanjiMissed
.c_str()),
254 _T("Test Results"), wxOK
| wxICON_INFORMATION
, this);
257 /* Switch the displayed panel */
258 pnlTest
->Show(false);
259 pnlConfig
->Show(true);
260 pnlConfig
->SetFocus();
261 this->GetSizer()->Layout();
262 jben
->gui
->GetMenuBar()->EnableTop(GUI_menuKanji
, true);
266 void PanelKanjiDrill::OnStop(wxCommandEvent
& ev
) {
268 /* If testing is not complete, prompt to make sure we want to quit. */
270 if(testKanji
.size()!=0) {
271 result
= wxMessageBox(_T("A test is still in progress! Are you sure?"), _T("Test in progress!"), wxYES_NO
| wxICON_EXCLAMATION
, this);
279 bool PanelKanjiDrill::TestInProgress() {return testing
;}
281 void PanelKanjiDrill::UpdateKanjiCountSpinner() {
282 int max
= jben
->kanjiList
->Size();
284 spnKanjiCount
->SetRange(1, max
);
285 int i
= spnKanjiCount
->GetValue();
286 if(i
<1) {i
=1; spnKanjiCount
->SetValue(1);}
287 if(i
>max
) {i
=max
; spnKanjiCount
->SetValue(max
);}
291 void PanelKanjiDrill::UpdateStartIndexSpinner() {
292 int max
= jben
->kanjiList
->Size();
293 int i
= spnKanjiCount
->GetValue();
294 int indexMax
= max
- (i
-1);
295 spnStartIndex
->SetRange(1, indexMax
);
296 i
= spnStartIndex
->GetValue();
297 if(i
<1) spnStartIndex
->SetValue(1);
298 if(i
>indexMax
) spnStartIndex
->SetValue(indexMax
);
301 void PanelKanjiDrill::OnKanjiCountChange(wxSpinEvent
& ev
) {
302 UpdateStartIndexSpinner();
305 void PanelKanjiDrill::Redraw() {
307 int max
= jben
->kanjiList
->Size();
309 UpdateKanjiCountSpinner();
310 UpdateStartIndexSpinner();
318 void PanelKanjiDrill::OnRdoRandom(wxCommandEvent
& ev
) {
319 spnStartIndex
->Enable(false);
322 void PanelKanjiDrill::OnRdoStartIndex(wxCommandEvent
& ev
) {
323 spnStartIndex
->Enable(true);
326 void PanelKanjiDrill::ShowNextKanji() {
327 /* Remove the current kanji, and get the new one */
329 if(currentKanjiIndex
!=-1)
330 testKanji
.erase(testKanji
.begin()+currentKanjiIndex
);
331 if(testKanji
.size()>0) {
332 currentKanjiIndex
= rand() % testKanji
.size();
333 currentKanji
= testKanji
[currentKanjiIndex
];
334 } else { /* If there's no more kanji to get... */
335 if(missedKanji
.size()>0) {
336 extraPractice
= true;
337 testKanji
= missedKanji
;
344 testKanji
.erase(testKanji
.begin()+currentKanjiIndex
);
345 if(testKanji
.size()>0) {
346 currentKanjiIndex
= rand() % testKanji
.size();
347 currentKanji
= testKanji
[currentKanjiIndex
];
348 } else { /* If there's no more kanji to get... */
353 /* Update CoveredTextBoxes with new info from KANJIDIC. */
358 txtKanji
->SetHiddenStr(wxString(currentKanji
));
359 txtOnyomi
->SetHiddenStr(jben
->dicts
->GetKanjidic()
360 ->GetOnyomiStr(currentKanji
));
361 txtKunyomi
->SetHiddenStr(jben
->dicts
->GetKanjidic()
362 ->GetKunyomiStr(currentKanji
));
363 txtEnglish
->SetHiddenStr(jben
->dicts
->GetKanjidic()
364 ->GetEnglishStr(currentKanji
));
366 /* Update the test status label */
368 if(totalTested
>0) score
= round(100000*
370 (double)totalTested
)/1000;
372 lblTestProgress
->SetLabel(wxString::Format(
373 _T("Current score: %d/%d (%0.3f%%) Test Progress: %d/%d (%0.3f%% done)"),
374 correct
, totalTested
, score
,
375 totalTested
, totalToTest
, round(100000*
377 double(totalToTest
))/1000));
379 lblTestProgress
->SetLabel(wxString::Format(
380 _T("Extra practice: %d remaining Final score: %d/%d (%0.3f%%)"),
381 testKanji
.size(), correct
, totalTested
, score
));
385 this->GetSizer()->Layout();
387 /* Uncover the field(s) appropriate for the current test mode. */
393 txtOnyomi
->Uncover();
394 txtKunyomi
->Uncover();
395 txtEnglish
->Uncover();
400 void PanelKanjiDrill::OnCorrect(wxCommandEvent
& ev
) {
404 } else lastWasCorrect
= true;
408 void PanelKanjiDrill::OnWrong(wxCommandEvent
& ev
) {
411 missedKanji
.push_back(currentKanji
);
412 } else lastWasCorrect
= false;