summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
Diffstat (limited to 'wx+')
-rw-r--r--wx+/app_main.h7
-rw-r--r--wx+/context_menu.h11
-rw-r--r--wx+/format_unit.cpp134
-rw-r--r--wx+/format_unit.h11
-rw-r--r--wx+/graph.cpp32
-rw-r--r--wx+/grid.cpp102
-rw-r--r--wx+/image_tools.h4
-rw-r--r--wx+/shell_execute.h6
-rw-r--r--wx+/string_conv.h6
9 files changed, 239 insertions, 74 deletions
diff --git a/wx+/app_main.h b/wx+/app_main.h
index e39a8b43..0177fbf3 100644
--- a/wx+/app_main.h
+++ b/wx+/app_main.h
@@ -36,13 +36,6 @@ bool& refMainWndStatus()
}
inline
-bool& refQueryEnd()
-{
- static bool status = false; //external linkage!
- return status;
-}
-
-inline
void setMainWindow(wxWindow* window)
{
wxTheApp->SetTopWindow(window);
diff --git a/wx+/context_menu.h b/wx+/context_menu.h
index 663596f9..9f2f844b 100644
--- a/wx+/context_menu.h
+++ b/wx+/context_menu.h
@@ -59,19 +59,22 @@ public:
void addSubmenu(const wxString& label, ContextMenu& submenu, const wxBitmap* bmp = nullptr) //invalidates submenu!
{
- wxMenuItem* newItem = new wxMenuItem(menu.get(), wxID_ANY, label, L"", wxITEM_NORMAL, submenu.menu.release()); //menu owns item!
- if (bmp) newItem->SetBitmap(*bmp); //do not set AFTER appending item! wxWidgets screws up for yet another crappy reason
- menu->Append(newItem);
//transfer submenu commands:
commandList.insert(submenu.commandList.begin(), submenu.commandList.end());
submenu.commandList.clear();
+
+ submenu.menu->SetNextHandler(menu.get()); //on wxGTK submenu events are not propagated to their parent menu by default!
+
+ wxMenuItem* newItem = new wxMenuItem(menu.get(), wxID_ANY, label, L"", wxITEM_NORMAL, submenu.menu.release()); //menu owns item, item owns submenu!
+ if (bmp) newItem->SetBitmap(*bmp); //do not set AFTER appending item! wxWidgets screws up for yet another crappy reason
+ menu->Append(newItem);
}
void popup(wxWindow& wnd) //show popup menu + process lambdas
{
//eventually all events from submenu items will be received by this menu
for (auto iter = commandList.begin(); iter != commandList.end(); ++iter)
- menu->Connect(iter->first, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(ContextMenu::onSelection), new GenericCommand(iter->second), /*pass ownership*/ this);
+ menu->Connect(iter->first, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(ContextMenu::onSelection), new GenericCommand(iter->second) /*pass ownership*/, this);
wnd.PopupMenu(menu.get());
wxTheApp->ProcessPendingEvents(); //make sure lambdas are evaluated before going out of scope;
diff --git a/wx+/format_unit.cpp b/wx+/format_unit.cpp
index f6d2e5c2..9d805f41 100644
--- a/wx+/format_unit.cpp
+++ b/wx+/format_unit.cpp
@@ -15,22 +15,18 @@
#ifdef FFS_WIN
#include <zen/win.h> //includes "windows.h"
#include <zen/win_ver.h>
-#endif
+#elif defined FFS_LINUX
+#include <clocale> //thousands separator
+#include <zen/utf.h> //
+#endif
-namespace
-{
-inline
-size_t getDigitCount(size_t number)
-{
- return number == 0 ? 1 : static_cast<size_t>(std::log10(static_cast<double>(number))) + 1;
-} //count number of digits
-}
+using namespace zen;
std::wstring zen::filesizeToShortString(Int64 size)
{
- //if (to<Int64>(size) < 0) return _("Error"); -> really? there's one exceptional case: a failed rename operation falls-back to copy + delete, reducing "bytes transferred" to potentially < 0!
+ //if (size < 0) return _("Error"); -> really? there's at least one exceptional case: a failed rename operation falls-back to copy + delete, reducing "bytes transferred" to potentially < 0!
if (numeric::abs(size) <= 999)
return replaceCpy(_P("1 Byte", "%x Bytes", to<int>(size)),
@@ -63,15 +59,14 @@ std::wstring zen::filesizeToShortString(Int64 size)
}
}
//print just three significant digits: 0,01 | 0,11 | 1,11 | 11,1 | 111
- const size_t leadDigitCount = getDigitCount(static_cast<size_t>(numeric::abs(filesize))); //number of digits before decimal point
- if (leadDigitCount == 0 || leadDigitCount > 3)
- return _("Error");
+ const size_t fullunits = static_cast<size_t>(numeric::abs(filesize));
+ const int precisionDigits = fullunits < 10 ? 2 : fullunits < 100 ? 1 : 0; //sprintf requires "int"
wchar_t buffer[50];
#ifdef __MINGW32__
- int charsWritten = ::snwprintf(buffer, 50, L"%.*f", static_cast<int>(3 - leadDigitCount), filesize); //MinGW does not comply to the C standard here
+ int charsWritten = ::snwprintf(buffer, 50, L"%.*f", precisionDigits, filesize); //MinGW does not comply to the C standard here
#else
- int charsWritten = std::swprintf(buffer, 50, L"%.*f", static_cast<int>(3 - leadDigitCount), filesize);
+ int charsWritten = std::swprintf(buffer, 50, L"%.*f", precisionDigits, filesize);
#endif
return charsWritten > 0 ? replaceCpy(output, L"%x", std::wstring(buffer, charsWritten)) : _("Error");
}
@@ -142,8 +137,114 @@ std::wstring zen::fractionToShortString(double fraction)
}
+#ifdef FFS_WIN
+namespace
+{
+bool getUserSetting(LCTYPE lt, UINT& setting)
+{
+ return ::GetLocaleInfo(LOCALE_USER_DEFAULT, //__in LCID Locale,
+ lt | LOCALE_RETURN_NUMBER, //__in LCTYPE LCType,
+ reinterpret_cast<LPTSTR>(&setting), //__out LPTSTR lpLCData,
+ sizeof(setting) / sizeof(TCHAR)) > 0; //__in int cchData
+}
+
+
+bool getUserSetting(LCTYPE lt, std::wstring& setting)
+{
+ int bufferSize = ::GetLocaleInfo(LOCALE_USER_DEFAULT, lt, nullptr, 0);
+ if (bufferSize > 0)
+ {
+ std::vector<wchar_t> buffer(bufferSize);
+ if (::GetLocaleInfo(LOCALE_USER_DEFAULT, //__in LCID Locale,
+ lt, //__in LCTYPE LCType,
+ &buffer[0], //__out LPTSTR lpLCData,
+ bufferSize) > 0) //__in int cchData
+ {
+ setting = &buffer[0]; //GetLocaleInfo() returns char count *including* 0-termination!
+ return true;
+ }
+ }
+ return false;
+}
+
+class IntegerFormat
+{
+public:
+ static const NUMBERFMT& get() { return getInst().fmt; }
+ static bool isValid() { return getInst().valid_; }
+
+private:
+ static const IntegerFormat& getInst()
+ {
+ static IntegerFormat inst; //not threadsafe in MSVC until C++11, but not required right now
+ return inst;
+ }
+
+ IntegerFormat() : fmt(), valid_(false)
+ {
+ //all we want is default NUMBERFMT, but set NumDigits to 0. what a disgrace:
+ fmt.NumDigits = 0;
+
+ std::wstring grouping;
+ if (getUserSetting(LOCALE_ILZERO, fmt.LeadingZero) &&
+ getUserSetting(LOCALE_SGROUPING, grouping) &&
+ getUserSetting(LOCALE_SDECIMAL, decimalSep) &&
+ getUserSetting(LOCALE_STHOUSAND, thousandSep) &&
+ getUserSetting(LOCALE_INEGNUMBER, fmt.NegativeOrder))
+ {
+ fmt.lpDecimalSep = &decimalSep[0]; //not used
+ fmt.lpThousandSep = &thousandSep[0];
+
+ //convert LOCALE_SGROUPING to Grouping: http://blogs.msdn.com/b/oldnewthing/archive/2006/04/18/578251.aspx
+ replace(grouping, L';', L"");
+ if (endsWith(grouping, L'0'))
+ grouping.resize(grouping.size() - 1);
+ else
+ grouping += L'0';
+ fmt.Grouping = stringTo<UINT>(grouping);
+ valid_ = true;
+ }
+ }
+
+ NUMBERFMT fmt;
+ std::wstring thousandSep;
+ std::wstring decimalSep;
+ bool valid_;
+};
+}
+#endif
+
+
std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number)
{
+#ifdef FFS_WIN
+ if (IntegerFormat::isValid())
+ {
+ int bufferSize = ::GetNumberFormat(LOCALE_USER_DEFAULT, 0, number.c_str(), &IntegerFormat::get(), nullptr, 0);
+ if (bufferSize > 0)
+ {
+ std::vector<wchar_t> buffer(bufferSize);
+ if (::GetNumberFormat(LOCALE_USER_DEFAULT, //__in LCID Locale,
+ 0, //__in DWORD dwFlags,
+ number.c_str(), //__in LPCTSTR lpValue,
+ &IntegerFormat::get(), //__in_opt const NUMBERFMT *lpFormat,
+ &buffer[0], //__out_opt LPTSTR lpNumberStr,
+ bufferSize) > 0) //__in int cchNumber
+ return &buffer[0]; //GetNumberFormat() returns char count *including* 0-termination!
+ }
+ }
+ return number;
+
+#else
+ //we have to include thousands separator ourselves; this doesn't work for all countries (e.g india), but is better than nothing
+
+ //::setlocale (LC_ALL, ""); -> implicitly called by wxLocale
+ const lconv* localInfo = ::localeconv(); //always bound according to doc
+ const std::wstring& thousandSep = utfCvrtTo<std::wstring>(localInfo->thousands_sep);
+ // why not working?
+ // THOUSANDS_SEPARATOR = std::use_facet<std::numpunct<wchar_t> >(std::locale("")).thousands_sep();
+ // DECIMAL_POINT = std::use_facet<std::numpunct<wchar_t> >(std::locale("")).decimal_point();
+
std::wstring output(number);
size_t i = output.size();
for (;;)
@@ -153,9 +254,10 @@ std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number)
i -= 3;
if (!isDigit(output[i - 1]))
break;
- output.insert(i, zen::getThousandsSeparator());
+ output.insert(i, thousandSep);
}
return output;
+#endif
}
/*
diff --git a/wx+/format_unit.h b/wx+/format_unit.h
index 71501db7..361e7d86 100644
--- a/wx+/format_unit.h
+++ b/wx+/format_unit.h
@@ -18,7 +18,7 @@ std::wstring remainingTimeToShortString(double timeInSec);
std::wstring fractionToShortString(double fraction); //within [0, 1]
template <class NumberType>
-std::wstring toStringSep(NumberType number); //convert number to std::wstring including thousands separator
+std::wstring toGuiString(NumberType number); //format integer number including thousands separator
std::wstring utcToLocalTimeString(Int64 utcTime); //throw std::runtime_error
@@ -42,12 +42,6 @@ std::wstring utcToLocalTimeString(Int64 utcTime); //throw std::runtime_error
-
-
-
-
-
-
//--------------- inline impelementation -------------------------------------------
namespace ffs_Impl
{
@@ -55,8 +49,9 @@ std::wstring includeNumberSeparator(const std::wstring& number);
}
template <class NumberType> inline
-std::wstring toStringSep(NumberType number)
+std::wstring toGuiString(NumberType number)
{
+ //assert_static(IsInteger<NumberType>::value); -> doesn't work for UInt64
return ffs_Impl::includeNumberSeparator(zen::numberTo<std::wstring>(number));
}
}
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index 9a64b3dd..fd68b548 100644
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -96,7 +96,7 @@ void drawYLabel(wxDC& dc, double& yMin, double& yMax, const wxRect& clientArea,
if (clientArea.GetHeight() <= 0 || clientArea.GetWidth() <= 0)
return;
- int optimalBlockHeight = 3 * dc.GetMultiLineTextExtent(wxT("1")).GetHeight();;
+ int optimalBlockHeight = 3 * dc.GetMultiLineTextExtent(L"1").GetHeight();;
double valRangePerBlock = (yMax - yMin) * optimalBlockHeight / clientArea.GetHeight();
valRangePerBlock = labelFmt.getOptimalBlockSize(valRangePerBlock);
@@ -114,7 +114,8 @@ void drawYLabel(wxDC& dc, double& yMin, double& yMax, const wxRect& clientArea,
//draw labels
{
wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192))); //light grey
- dc.SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("Arial") ));
+ wxDCTextColourChanger dummy2(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
+ dc.SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Arial"));
const int posLabel = drawLeft ? 0 : clientArea.GetWidth() - labelWidth;
const int posDataArea = drawLeft ? labelWidth : 0;
@@ -147,7 +148,7 @@ void drawXLabel(wxDC& dc, double& xMin, double& xMax, const wxRect& clientArea,
if (clientArea.GetHeight() <= 0 || clientArea.GetWidth() <= 0)
return;
- const int optimalBlockWidth = dc.GetMultiLineTextExtent(wxT("100000000000000")).GetWidth();
+ const int optimalBlockWidth = dc.GetMultiLineTextExtent(L"100000000000000").GetWidth();
double valRangePerBlock = (xMax - xMin) * optimalBlockWidth / clientArea.GetWidth();
valRangePerBlock = labelFmt.getOptimalBlockSize(valRangePerBlock);
@@ -166,7 +167,8 @@ void drawXLabel(wxDC& dc, double& xMin, double& xMax, const wxRect& clientArea,
//draw labels
{
wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192))); //light grey
- dc.SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("Arial") ));
+ wxDCTextColourChanger dummy2(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
+ dc.SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Arial"));
const int posLabel = drawBottom ? clientArea.GetHeight() - labelHeight : 0;
const int posDataArea = drawBottom ? 0 : labelHeight;
@@ -290,7 +292,8 @@ void Graph2D::OnMouseLeftUp(wxMouseEvent& event)
{
//fire off GraphSelectEvent
GraphSelectEvent evt(activeSel->refSelection());
- GetEventHandler()->AddPendingEvent(evt);
+ if (wxEvtHandler* evtHandler = GetEventHandler())
+ evtHandler->AddPendingEvent(evt);
oldSel.push_back(activeSel->refSelection());
}
@@ -342,10 +345,12 @@ private:
void Graph2D::render(wxDC& dc) const
{
{
- //draw everything including label background in natural window color by default (overwriting current background color)
- const wxColor backColor = wxPanel::GetClassDefaultAttributes().colBg != wxNullColour ?
- wxPanel::GetClassDefaultAttributes().colBg :
- wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
+ //clear everything, set label background color
+ // const wxColor backColor = wxPanel::GetClassDefaultAttributes().colBg != wxNullColour ?
+ // wxPanel::GetClassDefaultAttributes().colBg :
+ // wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
+ const wxColor backColor = GetBackgroundColour(); //user-configurable!
+
//wxDCBrushChanger dummy(dc, *wxTRANSPARENT_BRUSH); //sigh, who *invents* this stuff??? -> workaround for issue with wxBufferedPaintDC
DcBackgroundChanger dummy(dc, backColor);
dc.Clear();
@@ -395,8 +400,8 @@ void Graph2D::render(wxDC& dc) const
}
{
- //paint actual graph background (without labels) using window background color
- DcBackgroundChanger dummy(dc, GetBackgroundColour());
+ //paint actual graph background (without labels)
+ DcBackgroundChanger dummy(dc, *wxWHITE); //accessibility: we have to set both back- and foreground colors or none at all!
wxDCPenChanger dummy2(dc, wxColour(130, 135, 144)); //medium grey, the same Win7 uses for other frame borders
//dc.DrawRectangle(static_cast<const wxRect&>(dataArea).Inflate(1, 1)); //correct wxWidgets design mistakes
dc.DrawRectangle(dataArea);
@@ -507,10 +512,7 @@ void Graph2D::render(wxDC& dc) const
//wxDCBrushChanger dummy(dc, *wxTRANSPARENT_BRUSH);
wxDCBrushChanger dummy(dc, colSelect); //alpha channel (not yet) supported on wxMSW, so draw selection before graphs
- wxPen selPen(colSelect);
- //wxPen selPen(*wxBLACK);
- //selPen.SetStyle(wxSHORT_DASH);
- wxDCPenChanger dummy2(dc, selPen);
+ wxDCPenChanger dummy2(dc, colSelect);
for (auto i = allSelections.begin(); i != allSelections.end(); ++i)
{
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index 89891879..e1208109 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -16,15 +16,16 @@
#include <zen/tick_count.h>
#include <zen/string_tools.h>
#include <zen/scope_guard.h>
+#include <zen/utf.h>
#include "format_unit.h"
#ifdef FFS_LINUX
#include <gtk/gtk.h>
#endif
-
using namespace zen;
+
wxColor zen::getColorSelectionGradientFrom() { return wxColor(137, 172, 255); } //blue: H:158 S:255 V:196
wxColor zen::getColorSelectionGradientTo () { return wxColor(225, 234, 255); } // H:158 S:255 V:240
@@ -210,12 +211,55 @@ void GridData::drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bo
}
-void GridData::drawCellText(wxDC& dc, const wxRect& rect, const wxString& text, bool enabled, int alignment)
+namespace
{
- wxDCTextColourChanger dummy(dc, enabled ? dc.GetTextForeground() : wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
+#ifdef _MSC_VER
+#pragma warning(disable:4428) // VC wrongly issues warning C4428: universal-character-name encountered in source
+#endif
+const wchar_t ELLIPSIS = L'\u2026'; //...
+
+template <class Function> inline
+wxString getTruncatedText(const wxString& text, Function textFits)
+{
+ if (textFits(text))
+ return text;
+
+ //unlike Windows 7 Explorer, we truncate UTF-16 correctly: e.g. CJK-Ideogramm encodes to TWO wchar_t: utfCvrtTo<wxString>("\xf0\xa4\xbd\x9c");
+ size_t low = 0; //number of unicode chars!
+ size_t high = unicodeLength(text); //
+
+ for (;;)
+ {
+ const size_t middle = (low + high) / 2;
+ wxString candidate(strBegin(text), findUnicodePos(text, middle));
+ candidate += ELLIPSIS;
+
+ if (high - low <= 1)
+ return candidate;
+
+ if (textFits(candidate))
+ low = middle;
+ else
+ high = middle;
+ }
+}
+
+void drawTextLabelFitting(wxDC& dc, const wxString& text, const wxRect& rect, int alignment)
+{
DcClipper clip(dc, rect); //wxDC::DrawLabel doesn't care about width, WTF?
- dc.DrawLabel(text, rect, alignment);
+
+ //truncate large texts and add ellipsis
+ auto textFits = [&](const wxString& phrase) { return dc.GetTextExtent(phrase).GetWidth() <= rect.GetWidth(); };
+ dc.DrawLabel(getTruncatedText(text, textFits), rect, alignment);
+}
+}
+
+
+void GridData::drawCellText(wxDC& dc, const wxRect& rect, const wxString& text, bool enabled, int alignment)
+{
+ wxDCTextColourChanger dummy(dc, enabled ? dc.GetTextForeground() : wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
+ drawTextLabelFitting(dc, text, rect, alignment);
}
@@ -260,8 +304,8 @@ void GridData::drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool high
void GridData::drawColumnLabelText(wxDC& dc, const wxRect& rect, const wxString& text)
{
- DcClipper clip(dc, rect); //wxDC::DrawLabel doesn't care about witdh, WTF?
- dc.DrawLabel(text, rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
+ wxDCTextColourChanger dummy(dc, *wxBLACK); //accessibility: always set both foreground AND background colors!
+ drawTextLabelFitting(dc, text, rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
}
//----------------------------------------------------------------------------------------------------------------
@@ -481,7 +525,7 @@ public:
}
private:
- static wxString formatRow(size_t row) { return toStringSep(row + 1); } //convert number to std::wstring including thousands separator
+ static wxString formatRow(size_t row) { return toGuiString(row + 1); } //convert number to std::wstring including thousands separator
virtual bool AcceptsFocus() const { return false; }
@@ -495,7 +539,8 @@ private:
wxFont labelFont = GetFont();
labelFont.SetWeight(wxFONTWEIGHT_BOLD);
dc.SetFont(labelFont);
- dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+
+ wxDCTextColourChanger dummy(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
auto rowRange = getRowsOnClient(rect); //returns range [begin, end)
for (auto row = rowRange.first; row < rowRange.second; ++row)
@@ -513,6 +558,7 @@ private:
{
//clearArea(dc, rect, getColorRowLabel());
dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxWEST); //clear overlapping cells
+ wxDCTextColourChanger dummy3(dc, *wxBLACK); //accessibility: always set both foreground AND background colors!
//label text
wxRect textRect = rect;
@@ -621,7 +667,8 @@ private:
wxFont labelFont = GetFont();
labelFont.SetWeight(wxFONTWEIGHT_BOLD);
dc.SetFont(labelFont);
- dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+
+ wxDCTextColourChanger dummy(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
const int colLabelHeight = refParent().colLabelHeight;
@@ -847,6 +894,10 @@ private:
};
//----------------------------------------------------------------------------------------------------------------
+namespace
+{
+const wxEventType EVENT_GRID_HAS_SCROLLED = wxNewEventType(); //internal to Grid::MainWin::ScrollWindow()
+}
//----------------------------------------------------------------------------------------------------------------
class Grid::MainWin : public SubWindow
@@ -857,7 +908,10 @@ public:
ColLabelWin& colLabelWin) : SubWindow(parent),
rowLabelWin_(rowLabelWin),
colLabelWin_(colLabelWin),
- selectionAnchor(0) {}
+ selectionAnchor(0)
+ {
+ Connect(EVENT_GRID_HAS_SCROLLED, wxCommandEventHandler(MainWin::updateAfterScroll), nullptr, this);
+ }
void makeRowVisible(size_t row)
{
@@ -915,7 +969,8 @@ private:
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
dc.SetFont(GetFont());
- dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+
+ wxDCTextColourChanger dummy(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
const int rowHeight = rowLabelWin_.getRowHeight();
@@ -938,7 +993,7 @@ private:
{
//draw background lines
{
- DcClipper dummy(dc, rect); //solve issues with drawBackground() painting in area outside of rect (which is not also refreshed by renderCell()) -> keep small scope!
+ DcClipper dummy2(dc, rect); //solve issues with drawBackground() painting in area outside of rect (which is not also refreshed by renderCell()) -> keep small scope!
for (int row = rowFirst; row < rowLast; ++row)
drawBackground(*prov, dc, wxRect(cellAreaTL + wxPoint(0, row * rowHeight), wxSize(compWidth, rowHeight)), row, compPos);
}
@@ -992,8 +1047,12 @@ private:
{
const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition());
const auto row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 if no row at this position
- if (const auto colInfo = refParent().getColumnAtPos(absPos.x)) //returns (column type, compPos)
- sendEventNow(GridClickEvent(EVENT_GRID_MOUSE_LEFT_DOUBLE, event, row, colInfo->first, colInfo->second));
+ const auto colInfo = refParent().getColumnAtPos(absPos.x); //returns (column type, compPos)
+
+ const ColumnType colType = colInfo ? colInfo->first : DUMMY_COLUMN_TYPE;
+ const ptrdiff_t compPos = colInfo ? colInfo->second : -1;
+ //client is interested in all double-clicks, even those outside of the grid!
+ sendEventNow(GridClickEvent(EVENT_GRID_MOUSE_LEFT_DOUBLE, event, row, colType, compPos));
event.Skip();
}
@@ -1070,7 +1129,7 @@ private:
const auto colInfo = refParent().getColumnAtPos(absPos.x); //returns optional pair (column type, compPos)
const ColumnType colType = colInfo ? colInfo->first : DUMMY_COLUMN_TYPE; //we probably should notify even if colInfo is invalid!
- const size_t compPos = colInfo ? colInfo->second : 0;
+ const ptrdiff_t compPos = colInfo ? colInfo->second : -1;
//notify event
sendEventNow(GridClickEvent(event.RightUp() ? EVENT_GRID_MOUSE_RIGHT_UP : EVENT_GRID_MOUSE_LEFT_UP, event, row, colType, compPos));
@@ -1361,7 +1420,18 @@ private:
rowLabelWin_.ScrollWindow(0, dy, rect);
colLabelWin_.ScrollWindow(dx, 0, rect);
- refParent().updateWindowSizes(false); //row label width has changed -> do *not* update scrollbars: recursion on wxGTK!
+ //attention, wxGTK call sequence: wxScrolledWindow::Scroll() -> wxScrolledHelperNative::Scroll() -> wxScrolledHelperNative::DoScroll()
+ //which *first* calls us, MainWin::ScrollWindow(), and *then* internally updates m_yScrollPosition
+ //=> we cannot use CalcUnscrolledPosition() here which gives the wrong/outdated value!!!
+ //=> we need to update asynchronously:
+ wxCommandEvent scrollEvent(EVENT_GRID_HAS_SCROLLED);
+ if (wxEvtHandler* evtHandler = GetEventHandler())
+ evtHandler->AddPendingEvent(scrollEvent);
+ }
+
+ void updateAfterScroll(wxCommandEvent&)
+ {
+ refParent().updateWindowSizes(false); //row label width has changed -> do *not* update scrollbars: recursion on wxGTK! -> still a problem, now that we're called async??
rowLabelWin_.Update(); //update while dragging scroll thumb
}
diff --git a/wx+/image_tools.h b/wx+/image_tools.h
index 82fd88cc..8a2a43ed 100644
--- a/wx+/image_tools.h
+++ b/wx+/image_tools.h
@@ -53,9 +53,9 @@ void move(wxImage& img, int up, int left)
inline
wxBitmap greyScale(const wxBitmap& bmp)
{
- wxImage output = bmp.ConvertToImage().ConvertToGreyscale(1.0/3, 1.0/3, 1.0/3); //treat all channels equally!
+ wxImage output = bmp.ConvertToImage().ConvertToGreyscale(1.0 / 3, 1.0 / 3, 1.0 / 3); //treat all channels equally!
//wxImage output = bmp.ConvertToImage().ConvertToGreyscale();
- adjustBrightness(output, 170);
+ adjustBrightness(output, 160);
return output;
}
diff --git a/wx+/shell_execute.h b/wx+/shell_execute.h
index 9de30980..953efc43 100644
--- a/wx+/shell_execute.h
+++ b/wx+/shell_execute.h
@@ -71,7 +71,7 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo
{
wxString cmdFmt = L"File: " + filename + L"\nArg: " + arguments;
- wxMessageBox(replaceCpy(_("Invalid command line: %x"), L"%x", L"\n" + cmdFmt) + L"\n\n" + getLastErrorFormatted());
+ wxMessageBox(_("Invalid command line:") + L"\n" + cmdFmt + L"\n\n" + getLastErrorFormatted());
return;
}
@@ -86,10 +86,10 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
if (type == EXEC_TYPE_SYNC)
{
//Posix::system - execute a shell command
- int rv = ::system(utf8CvrtTo<std::string>(command).c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
+ int rv = ::system(utfCvrtTo<std::string>(command).c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
if (rv == -1 || WEXITSTATUS(rv) == 127) //http://linux.die.net/man/3/system "In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127)"
{
- wxMessageBox(replaceCpy(_("Invalid command line: %x"), L"%x", L"\n" + command));
+ wxMessageBox(_("Invalid command line:") + L"\n" + command);
return;
}
}
diff --git a/wx+/string_conv.h b/wx+/string_conv.h
index b23f6947..ba6f8d48 100644
--- a/wx+/string_conv.h
+++ b/wx+/string_conv.h
@@ -7,15 +7,15 @@
#ifndef STRINGCONV_H_INCLUDED
#define STRINGCONV_H_INCLUDED
-#include <zen/utf8.h>
+#include <zen/utf.h>
#include <wx/string.h>
#include <zen/zstring.h>
namespace zen
{
//conversion between Zstring and wxString
-inline wxString toWx(const Zstring& str) { return utf8CvrtTo<wxString>(str); }
-inline Zstring toZ(const wxString& str) { return utf8CvrtTo<Zstring>(str); }
+inline wxString toWx(const Zstring& str) { return utfCvrtTo<wxString>(str); }
+inline Zstring toZ(const wxString& str) { return utfCvrtTo<Zstring>(str); }
inline std::vector<Zstring> toZ(const std::vector<wxString>& strList)
{
bgstack15