summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
Diffstat (limited to 'wx+')
-rw-r--r--wx+/choice_enum.h2
-rw-r--r--wx+/graph.cpp22
-rw-r--r--wx+/graph.h4
-rw-r--r--wx+/grid.cpp17
-rw-r--r--wx+/grid.h4
-rw-r--r--wx+/image_resources.cpp36
-rw-r--r--wx+/image_tools.cpp58
-rw-r--r--wx+/image_tools.h3
8 files changed, 93 insertions, 53 deletions
diff --git a/wx+/choice_enum.h b/wx+/choice_enum.h
index 626aa39a..a590861a 100644
--- a/wx+/choice_enum.h
+++ b/wx+/choice_enum.h
@@ -41,7 +41,7 @@ struct EnumDescrList
{
EnumDescrList& add(Enum value, const wxString& text, const wxString& tooltip = {})
{
- descrList.push_back({ value, { text, tooltip } });
+ descrList.push_back({value, {text, tooltip}});
return *this;
}
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index ba87299e..be75ac4d 100644
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -36,7 +36,7 @@ double zen::nextNiceNumber(double blockSize) //round to next number which is a c
assert(1 <= a && a < 10);
//have a look at leading two digits: "nice" numbers start with 1, 2, 2.5 and 5
- const double steps[] = { 1, 2, 2.5, 5, 10 };
+ const double steps[] = {1, 2, 2.5, 5, 10};
return e * numeric::nearMatch(a, std::begin(steps), std::end(steps));
}
@@ -48,16 +48,16 @@ wxColor getDefaultColor(size_t pos)
switch (pos % 10)
{
//*INDENT-OFF*
- case 0: return { 0, 69, 134 }; //blue
- case 1: return { 255, 66, 14 }; //red
- case 2: return { 255, 211, 32 }; //yellow
- case 3: return { 87, 157, 28 }; //green
- case 4: return { 126, 0, 33 }; //royal
- case 5: return { 131, 202, 255 }; //light blue
- case 6: return { 49, 64, 4 }; //dark green
- case 7: return { 174, 207, 0 }; //light green
- case 8: return { 75, 31, 111 }; //purple
- case 9: return { 255, 149, 14 }; //orange
+ case 0: return { 0, 69, 134}; //blue
+ case 1: return {255, 66, 14}; //red
+ case 2: return {255, 211, 32}; //yellow
+ case 3: return { 87, 157, 28}; //green
+ case 4: return {126, 0, 33}; //royal
+ case 5: return {131, 202, 255}; //light blue
+ case 6: return { 49, 64, 4}; //dark green
+ case 7: return {174, 207, 0}; //light green
+ case 8: return { 75, 31, 111}; //purple
+ case 9: return {255, 149, 14}; //orange
//*INDENT-ON*
}
assert(false);
diff --git a/wx+/graph.h b/wx+/graph.h
index c843b09b..288ef9e7 100644
--- a/wx+/graph.h
+++ b/wx+/graph.h
@@ -218,7 +218,7 @@ public:
void addCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes());
void clearCurves() { curves_.clear(); }
- static wxColor getBorderColor() { return { 130, 135, 144 }; } //medium grey, the same Win7 uses for other frame borders => not accessible! but no big deal...
+ static wxColor getBorderColor() { return {130, 135, 144}; } //medium grey, the same Win7 uses for other frame borders => not accessible! but no big deal...
class MainAttributes
{
@@ -330,7 +330,7 @@ private:
CurveList curves_;
//perf!!! generating the font is *very* expensive! => buffer for Graph2D::render()!
- const wxFont labelFont_ { wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Arial" };
+ const wxFont labelFont_{wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Arial"};
};
}
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index cd91b1af..0111ccf7 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -27,8 +27,8 @@ using namespace zen;
//let's NOT create wxWidgets objects statically:
-wxColor GridData::getColorSelectionGradientFrom() { return { 137, 172, 255 }; } //blue: HSL: 158, 255, 196 HSV: 222, 0.46, 1
-wxColor GridData::getColorSelectionGradientTo () { return { 225, 234, 255 }; } // HSL: 158, 255, 240 HSV: 222, 0.12, 1
+wxColor GridData::getColorSelectionGradientFrom() { return {137, 172, 255}; } //blue: HSL: 158, 255, 196 HSV: 222, 0.46, 1
+wxColor GridData::getColorSelectionGradientTo () { return {225, 234, 255}; } // HSL: 158, 255, 240 HSV: 222, 0.12, 1
int GridData::getColumnGapLeft() { return fastFromDIP(4); }
@@ -493,8 +493,8 @@ public:
const int yFrom = refParent().CalcUnscrolledPosition(clientRect.GetTopLeft ()).y;
const int yTo = refParent().CalcUnscrolledPosition(clientRect.GetBottomRight()).y;
- return { std::max(yFrom / rowHeight_, 0),
- std::min<ptrdiff_t>((yTo / rowHeight_) + 1, refParent().getRowCount()) };
+ return {std::max(yFrom / rowHeight_, 0),
+ std::min<ptrdiff_t>((yTo / rowHeight_) + 1, refParent().getRowCount())};
}
private:
@@ -1351,6 +1351,7 @@ private:
return;
const double mouseDragSpeedIncScrollU = MOUSE_DRAG_ACCELERATION_DIP * wnd_.rowLabelWin_.getRowHeight() / pixelsPerUnitY; //unit: [scroll units / (DIP * sec)]
+ //design alternative: "Dynamic autoscroll based on escape velocity": https://devblogs.microsoft.com/oldnewthing/20210128-00/?p=104768
auto autoScroll = [&](int overlapPix, double& toScroll)
{
@@ -1986,7 +1987,7 @@ void Grid::setColumnConfig(const std::vector<Grid::ColAttributes>& attr)
assert(ca.type != ColumnType::none);
if (ca.visible)
- visCols.push_back({ ca.type, ca.offset, std::max(ca.stretch, 0) });
+ visCols.push_back({ca.type, ca.offset, std::max(ca.stretch, 0)});
}
//"ownership" of visible columns is now within Grid
@@ -2101,10 +2102,10 @@ Grid::ColumnPosInfo Grid::getColumnAtPos(int posX) const
{
accWidth += cw.width;
if (posX < accWidth)
- return { cw.type, posX + cw.width - accWidth, cw.width };
+ return {cw.type, posX + cw.width - accWidth, cw.width};
}
}
- return { ColumnType::none, 0, 0 };
+ return {ColumnType::none, 0, 0};
}
@@ -2386,7 +2387,7 @@ std::vector<Grid::ColumnWidth> Grid::getColWidths(int mainWinWidth) const //eval
else
width = std::max(width, 0); //support smaller width than COLUMN_MIN_WIDTH_DIP if set via configuration
- output.push_back({ vc.type, width });
+ output.push_back({vc.type, width});
}
return output;
}
diff --git a/wx+/grid.h b/wx+/grid.h
index 8d68ffd7..4de76b66 100644
--- a/wx+/grid.h
+++ b/wx+/grid.h
@@ -387,7 +387,7 @@ std::vector<Grid::ColAttributes> convertColAttributes(const std::vector<ColAttrR
{
std::vector<Grid::ColAttributes> output;
for (const ColAttrReal& ca : makeConsistent(attribs, defaults))
- output.push_back({ static_cast<ColumnType>(ca.type), ca.offset, ca.stretch, ca.visible });
+ output.push_back({static_cast<ColumnType>(ca.type), ca.offset, ca.stretch, ca.visible});
return output;
}
@@ -399,7 +399,7 @@ std::vector<ColAttrReal> convertColAttributes(const std::vector<Grid::ColAttribu
std::vector<ColAttrReal> output;
for (const Grid::ColAttributes& ca : attribs)
- output.push_back({ static_cast<ColTypeReal>(ca.type), ca.offset, ca.stretch, ca.visible });
+ output.push_back({static_cast<ColTypeReal>(ca.type), ca.offset, ca.stretch, ca.visible});
return output;
}
}
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
index 42114ebb..fbfeb0d8 100644
--- a/wx+/image_resources.cpp
+++ b/wx+/image_resources.cpp
@@ -50,27 +50,23 @@ ImageHolder xbrzScale(int width, int height, const unsigned char* imageRgb, cons
*out++ = xbrz::makePixel(*alpha++, rgb[0], rgb[1], rgb[2]);
}
//-----------------------------------------------------
- xbrz::scale(hqScale, //size_t factor, //valid range: 2 - SCALE_FACTOR_MAX
- argbSrc, //const uint32_t* src,
- xbrTrg, //uint32_t* trg,
- width, height, //int srcWidth, int srcHeight,
- xbrz::ColorFormat::ARGB_UNBUFFERED); //ColorFormat colFmt,
- //test: total xBRZ scaling time with ARGB: 300ms, ARGB_UNBUFFERED: 50ms
+ xbrz::scale(hqScale, //size_t factor - valid range: 2 - SCALE_FACTOR_MAX
+ argbSrc, //const uint32_t* src
+ xbrTrg, //uint32_t* trg
+ width, height, //int srcWidth, int srcHeight
+ xbrz::ColorFormat::argbUnbuffered); //ColorFormat colFmt
+ //test: total xBRZ scaling time with ARGB: 300ms, ARGB unbuffered: 50ms
//-----------------------------------------------------
//convert BGRA to RGB + alpha
ImageHolder trgImg(hqWidth, hqHeight, true /*withAlpha*/);
- {
- unsigned char* rgb = trgImg.getRgb();
- unsigned char* alpha = trgImg.getAlpha();
- std::for_each(xbrTrg, xbrTrg + hqWidth * hqHeight, [&](uint32_t col)
- {
- *alpha++ = xbrz::getAlpha(col);
- *rgb++ = xbrz::getRed (col);
- *rgb++ = xbrz::getGreen(col);
- *rgb++ = xbrz::getBlue (col);
- });
- }
+ std::for_each(xbrTrg, xbrTrg + hqWidth * hqHeight, [rgb = trgImg.getRgb(), alpha = trgImg.getAlpha()](uint32_t col) mutable
+ {
+ *alpha++ = xbrz::getAlpha(col);
+ *rgb++ = xbrz::getRed (col);
+ *rgb++ = xbrz::getGreen(col);
+ *rgb++ = xbrz::getBlue (col);
+ });
return trgImg;
}
@@ -128,7 +124,7 @@ private:
Protected<std::vector<std::pair<std::string, ImageHolder>>> result_;
using TaskType = FunctionReturnTypeT<decltype(&getScalerTask)>;
- std::optional<ThreadGroup<TaskType>> threadGroup_{ ThreadGroup<TaskType>(std::max<int>(std::thread::hardware_concurrency(), 1), Zstr("xBRZ Scaler")) };
+ std::optional<ThreadGroup<TaskType>> threadGroup_{ThreadGroup<TaskType>(std::max<int>(std::thread::hardware_concurrency(), 1), Zstr("xBRZ Scaler"))};
//hardware_concurrency() == 0 if "not computable or well defined"
};
@@ -296,8 +292,8 @@ const wxImage& ImageBuffer::getImage(const std::string& name, int maxWidth /*opt
if (rawImg.GetHeight() >= outHeight) //=> skip needless xBRZ upscaling
it = imagesOut_.emplace(imkey, shrinkImage(rawImg, -1 /*maxWidth*/, outHeight)).first;
else if (rawImg.GetHeight() >= 0.9 * outHeight) //almost there: also no need for xBRZ-scale
- //however: for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale"!
- it = imagesOut_.emplace(imkey, rawImg.Scale(numeric::intDivRound(outHeight * rawImg.GetWidth(), rawImg.GetHeight()), outHeight, wxIMAGE_QUALITY_BILINEAR)).first;
+ it = imagesOut_.emplace(imkey, bilinearScale(rawImg, numeric::intDivRound(outHeight * rawImg.GetWidth(), rawImg.GetHeight()), outHeight)).first;
+ //however: for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale"
else
it = imagesOut_.emplace(imkey, shrinkImage(getScaledImage(name), -1 /*maxWidth*/, outHeight)).first;
}
diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp
index 6ba95c5e..bbc8cee7 100644
--- a/wx+/image_tools.cpp
+++ b/wx+/image_tools.cpp
@@ -8,6 +8,7 @@
#include <zen/string_tools.h>
#include <zen/zstring.h>
#include <wx/app.h>
+#include <xBRZ/src/xbrz_tools.h>
using namespace zen;
@@ -91,12 +92,12 @@ void copyImageLayover(const wxImage& src,
for (int x = 0; x < srcWidth; ++x)
{
const int w1 = *srcAlpha; //alpha-composition interpreted as weighted average
- const int w2 = *trgAlpha * (255 - w1) / 255;
+ const int w2 = numeric::intDivRound(*trgAlpha * (255 - w1), 255);
const int wSum = w1 + w2;
auto calcColor = [w1, w2, wSum](unsigned char colsrc, unsigned char colTrg)
{
- return static_cast<unsigned char>(wSum == 0 ? 0 : (colsrc * w1 + colTrg * w2) / wSum);
+ return static_cast<unsigned char>(wSum == 0 ? 0 : numeric::intDivRound(colsrc * w1 + colTrg * w2, wSum));
};
trgRgb[0] = calcColor(srcRgb[0], trgRgb[0]);
trgRgb[1] = calcColor(srcRgb[1], trgRgb[1]);
@@ -138,7 +139,7 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay
const int img2Height = img2.GetHeight();
const wxSize newSize = dir == ImageStackLayout::horizontal ?
- wxSize(img1Width + gap + img2Width, std::max(img1Height, img2Height)) :
+ wxSize(img1Width + gap + img2Width, std::max(img1Height, img2Height)) :
wxSize(std::max(img1Width, img2Width), img1Height + gap + img2Height);
wxImage output(newSize);
@@ -181,7 +182,7 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const
//assert(!contains(text, L"&")); //accelerator keys not supported here
wxString textFmt = replaceCpy(text, L"&", L"", false);
- const std::vector<std::pair<wxString, wxSize>> lineInfo = getTextExtentInfo(textFmt, font);
+ const std::vector<std::pair<wxString, wxSize>> lineInfo = getTextExtentInfo(textFmt, font);
int maxWidth = 0;
int lineHeight = 0;
@@ -197,8 +198,8 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const
{
wxMemoryDC dc(newBitmap);
- if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
- dc.SetLayoutDirection(wxLayout_RightToLeft); //handle e.g. "weak" bidi characters: -> arrows in hebrew/arabic
+ if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
+ dc.SetLayoutDirection(wxLayout_RightToLeft); //handle e.g. "weak" bidi characters: -> arrows in hebrew/arabic
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
@@ -238,7 +239,7 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const
for (int i = 0; i < pixelCount; ++i)
{
//black(0,0,0) becomes wxIMAGE_ALPHA_OPAQUE(255), while white(255,255,255) becomes wxIMAGE_ALPHA_TRANSPARENT(0)
- *alpha++ = static_cast<unsigned char>((255 - rgb[0] + 255 - rgb[1] + 255 - rgb[2]) / 3); //mixed-mode arithmetics!
+ *alpha++ = static_cast<unsigned char>(numeric::intDivRound(3 * 255 - rgb[0] - rgb[1] - rgb[2], 3)); //mixed-mode arithmetics!
*rgb++ = col.Red (); //
*rgb++ = col.Green(); //apply actual text color
@@ -312,6 +313,46 @@ wxImage zen::resizeCanvas(const wxImage& img, wxSize newSize, int alignment)
}
+wxImage zen::bilinearScale(const wxImage& img, int width, int height)
+{
+ assert(img.HasAlpha());
+ const auto imgReader = [rgb = img.GetData(), alpha = img.GetAlpha(), srcWidth = img.GetSize().x](int x, int y, xbrz::BytePixel& pix)
+ {
+ const int idx = y * srcWidth + x;
+ const unsigned char* const ptr = rgb + idx * 3;
+
+ const unsigned char a = alpha[idx];
+ pix[0] = a;
+ pix[1] = xbrz::premultiply(ptr[0], a); //r
+ pix[2] = xbrz::premultiply(ptr[1], a); //g
+ pix[3] = xbrz::premultiply(ptr[2], a); //b
+ };
+
+ wxImage imgOut(width, height);
+ imgOut.SetAlpha();
+
+ const auto imgWriter = [rgb = imgOut.GetData(), alpha = imgOut.GetAlpha()](const xbrz::BytePixel& pix) mutable
+ {
+ const unsigned char a = pix[0];
+ * alpha++ = a;
+ * rgb++ = xbrz::demultiply(pix[1], a); //r
+ *rgb++ = xbrz::demultiply(pix[2], a); //g
+ *rgb++ = xbrz::demultiply(pix[3], a); //b
+ };
+
+ xbrz::bilinearScaleSimple(imgReader, //PixReader srcReader
+ img.GetSize().x, //int srcWidth
+ img.GetSize().y, //int srcHeight
+ imgWriter, //PixWriter trgWriter
+ width, //int trgWidth
+ height, //int trgHeight
+ 0, //int yFirst
+ height); //int yLast
+ return imgOut;
+ //return img.Scale(width, height, wxIMAGE_QUALITY_BILINEAR);
+}
+
+
wxImage zen::shrinkImage(const wxImage& img, int maxWidth /*optional*/, int maxHeight /*optional*/)
{
wxSize newSize = img.GetSize();
@@ -330,8 +371,7 @@ wxImage zen::shrinkImage(const wxImage& img, int maxWidth /*optional*/, int maxH
if (newSize == img.GetSize())
return img;
- return img.Scale(newSize.x, newSize.y, wxIMAGE_QUALITY_BILINEAR); //looks sharper than wxIMAGE_QUALITY_HIGH!
- //perf: use xbrz::bilinearScale instead? only about 10% shorter runtime
+ return bilinearScale(img, newSize.x, newSize.y); //looks sharper than wxIMAGE_QUALITY_HIGH!
}
diff --git a/wx+/image_tools.h b/wx+/image_tools.h
index 0f0fb9c2..c2fed4c1 100644
--- a/wx+/image_tools.h
+++ b/wx+/image_tools.h
@@ -50,6 +50,9 @@ void convertToVanillaImage(wxImage& img); //add alpha channel if missing + remov
//wxColor hsvColor(double h, double s, double v); //h within [0, 360), s, v within [0, 1]
+//does *not* fuck up alpha channel like naive bilinear implementations, e.g. wxImage::Scale()
+wxImage bilinearScale(const wxImage& img, int width, int height);
+
wxImage shrinkImage(const wxImage& img, int maxWidth /*optional*/, int maxHeight /*optional*/);
inline wxImage shrinkImage(const wxImage& img, int maxSize) { return shrinkImage(img, maxSize, maxSize); }
bgstack15