mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 13:37:00 -04:00
Themed checkboxes
Slightly larger items in (multiple) choice viewers
This commit is contained in:
@@ -116,7 +116,7 @@ String ChoiceField::Choice::choiceName(int id) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _("");
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
String ChoiceField::Choice::choiceNameNice(int id) const {
|
String ChoiceField::Choice::choiceNameNice(int id) const {
|
||||||
@@ -165,14 +165,9 @@ ChoiceStyle::ChoiceStyle(const ChoiceFieldP& field)
|
|||||||
, choice_images_initialized(false)
|
, choice_images_initialized(false)
|
||||||
, combine(COMBINE_NORMAL)
|
, combine(COMBINE_NORMAL)
|
||||||
, alignment(ALIGN_STRETCH)
|
, alignment(ALIGN_STRETCH)
|
||||||
, thumbnails(nullptr)
|
|
||||||
, content_width(0.0), content_height(0.0)
|
, content_width(0.0), content_height(0.0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ChoiceStyle::~ChoiceStyle() {
|
|
||||||
delete thumbnails;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChoiceStyle::initImage() {
|
void ChoiceStyle::initImage() {
|
||||||
if (image.isSet() || choice_images.empty()) return;
|
if (image.isSet() || choice_images.empty()) return;
|
||||||
// for, for example:
|
// for, for example:
|
||||||
@@ -234,10 +229,9 @@ void ChoiceStyle::checkContentDependencies(Context& ctx, const Dependency& dep)
|
|||||||
void ChoiceStyle::invalidate() {
|
void ChoiceStyle::invalidate() {
|
||||||
// TODO : this is also done in update(), once should be enough
|
// TODO : this is also done in update(), once should be enough
|
||||||
// Update choice images and thumbnails
|
// Update choice images and thumbnails
|
||||||
int end = field().choices->lastId();
|
for (auto& thumbnail : thumbnails) {
|
||||||
thumbnails_status.resize(end, THUMB_NOT_MADE);
|
ChoiceThumbnailLock lock(thumbnail.mutex);
|
||||||
for (int i = 0 ; i < end ; ++i) {
|
if (thumbnail.status == THUMB_OK) thumbnail.status = THUMB_CHANGED;
|
||||||
if (thumbnails_status[i] == THUMB_OK) thumbnails_status[i] = THUMB_CHANGED;
|
|
||||||
}
|
}
|
||||||
tellListeners(CHANGE_OTHER);
|
tellListeners(CHANGE_OTHER);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#include <script/scriptable.hpp>
|
#include <script/scriptable.hpp>
|
||||||
#include <script/image.hpp>
|
#include <script/image.hpp>
|
||||||
#include <wx/image.h>
|
#include <wx/image.h>
|
||||||
class wxImageList;
|
#include <mutex>
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ChoiceField
|
// ----------------------------------------------------------------------------- : ChoiceField
|
||||||
|
|
||||||
@@ -134,12 +134,30 @@ enum ThumbnailStatus
|
|||||||
, THUMB_CHANGED // there is an image, but it may need to be updated
|
, THUMB_CHANGED // there is an image, but it may need to be updated
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ChoiceThumbnail {
|
||||||
|
public:
|
||||||
|
ThumbnailStatus status = THUMB_NOT_MADE;
|
||||||
|
wxBitmap bitmap;
|
||||||
|
std::recursive_mutex mutex;
|
||||||
|
};
|
||||||
|
using ChoiceThumbnailLock = std::lock_guard<std::recursive_mutex>;
|
||||||
|
|
||||||
|
// vector of thumbnails without a copy constructor
|
||||||
|
class ChoiceThumbnails : public std::vector<ChoiceThumbnail> {
|
||||||
|
public:
|
||||||
|
ChoiceThumbnails() {}
|
||||||
|
ChoiceThumbnails(ChoiceThumbnails const&) {} // don't copy
|
||||||
|
inline void resize(size_t n) {
|
||||||
|
// rebuilds the vector in one go, doesn't require move or copy constructor
|
||||||
|
std::vector<ChoiceThumbnail>::operator = (std::vector<ChoiceThumbnail>(n));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// The Style for a ChoiceField
|
/// The Style for a ChoiceField
|
||||||
class ChoiceStyle : public Style {
|
class ChoiceStyle : public Style {
|
||||||
public:
|
public:
|
||||||
ChoiceStyle(const ChoiceFieldP& field);
|
ChoiceStyle(const ChoiceFieldP& field);
|
||||||
DECLARE_STYLE_TYPE(Choice);
|
DECLARE_STYLE_TYPE(Choice);
|
||||||
~ChoiceStyle();
|
|
||||||
|
|
||||||
ChoicePopupStyle popup_style; ///< Style of popups/menus
|
ChoicePopupStyle popup_style; ///< Style of popups/menus
|
||||||
ChoiceRenderStyle render_style; ///< Style of rendering
|
ChoiceRenderStyle render_style; ///< Style of rendering
|
||||||
@@ -149,8 +167,7 @@ class ChoiceStyle : public Style {
|
|||||||
bool choice_images_initialized;
|
bool choice_images_initialized;
|
||||||
ImageCombine combine; ///< Combining mode for drawing the images
|
ImageCombine combine; ///< Combining mode for drawing the images
|
||||||
Alignment alignment; ///< Alignment of images
|
Alignment alignment; ///< Alignment of images
|
||||||
wxImageList* thumbnails; ///< Thumbnails for the choices
|
ChoiceThumbnails thumbnails; ///< Thumbnails for the choices
|
||||||
vector<ThumbnailStatus> thumbnails_status; ///< Which thumbnails are up to date?
|
|
||||||
// information from image rendering
|
// information from image rendering
|
||||||
double content_width, content_height; ///< Size of the rendered image/text
|
double content_width, content_height; ///< Size of the rendered image/text
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class DropDownHider;
|
|||||||
/// A popup/drop down window displaying a list of items
|
/// A popup/drop down window displaying a list of items
|
||||||
/** This class is an abstract base for various drop down lists */
|
/** This class is an abstract base for various drop down lists */
|
||||||
class DropDownList : public wxPopupWindow {
|
class DropDownList : public wxPopupWindow {
|
||||||
public:
|
public:
|
||||||
~DropDownList();
|
~DropDownList();
|
||||||
/// Create a drop down list, possibly a sub menu
|
/// Create a drop down list, possibly a sub menu
|
||||||
/** the viewer will be notified to redraw its drop down icon */
|
/** the viewer will be notified to redraw its drop down icon */
|
||||||
@@ -40,7 +40,7 @@ class DropDownList : public wxPopupWindow {
|
|||||||
/// Takes a mouse event from the parent, show/hide as appropriate
|
/// Takes a mouse event from the parent, show/hide as appropriate
|
||||||
bool onMouseInParent(wxMouseEvent&, bool open_in_place);
|
bool onMouseInParent(wxMouseEvent&, bool open_in_place);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// Prepare for showing the list
|
/// Prepare for showing the list
|
||||||
virtual void onShow() {}
|
virtual void onShow() {}
|
||||||
@@ -85,7 +85,7 @@ class DropDownList : public wxPopupWindow {
|
|||||||
RealSize item_size; ///< Size of an item;
|
RealSize item_size; ///< Size of an item;
|
||||||
RealSize icon_size; ///< Size of icons;
|
RealSize icon_size; ///< Size of icons;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --------------------------------------------------- : Data
|
// --------------------------------------------------- : Data
|
||||||
|
|
||||||
size_t selected_item; ///< The item that is selected, or NO_SELECTION
|
size_t selected_item; ///< The item that is selected, or NO_SELECTION
|
||||||
@@ -124,7 +124,7 @@ class DropDownList : public wxPopupWindow {
|
|||||||
void draw(DC& dc);
|
void draw(DC& dc);
|
||||||
void drawItem(DC& dc, int y, size_t item);
|
void drawItem(DC& dc, int y, size_t item);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void redrawArrowOnParent(); // allow override
|
virtual void redrawArrowOnParent(); // allow override
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -141,8 +141,7 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) {
|
|||||||
worker->Create();
|
worker->Create();
|
||||||
worker->Run();
|
worker->Run();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Image img;
|
Image img;
|
||||||
try {
|
try {
|
||||||
img = request->generate();
|
img = request->generate();
|
||||||
|
|||||||
+39
-34
@@ -382,6 +382,17 @@ wxImage load_resource_tool_image(const String& name) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Platform look
|
// ----------------------------------------------------------------------------- : Platform look
|
||||||
|
|
||||||
|
#if wxUSE_UXTHEME && defined(__WXMSW__)
|
||||||
|
RECT msw_rect(wxRect const& rect, int dl = 0, int dt = 0, int dr = 0, int db=0) {
|
||||||
|
RECT r;
|
||||||
|
r.left = rect.x - dl;
|
||||||
|
r.top = rect.y - dt;
|
||||||
|
r.right = rect.x + rect.width + dr;
|
||||||
|
r.bottom = rect.y + rect.height + db;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Draw a basic 3D border
|
// Draw a basic 3D border
|
||||||
void draw3DBorder(DC& dc, int x1, int y1, int x2, int y2) {
|
void draw3DBorder(DC& dc, int x1, int y1, int x2, int y2) {
|
||||||
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW));
|
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW));
|
||||||
@@ -400,14 +411,10 @@ void draw3DBorder(DC& dc, int x1, int y1, int x2, int y2) {
|
|||||||
|
|
||||||
void draw_control_box(Window* win, DC& dc, const wxRect& rect, bool focused, bool enabled) {
|
void draw_control_box(Window* win, DC& dc, const wxRect& rect, bool focused, bool enabled) {
|
||||||
#if wxUSE_UXTHEME && defined(__WXMSW__)
|
#if wxUSE_UXTHEME && defined(__WXMSW__)
|
||||||
RECT r;
|
RECT r = msw_rect(rect, 1,1,1,1);
|
||||||
if (wxUxThemeIsActive()) {
|
if (wxUxThemeIsActive()) {
|
||||||
HTHEME hTheme = (HTHEME)::OpenThemeData(GetHwndOf(win), L"EDIT");
|
HTHEME hTheme = (HTHEME)::OpenThemeData(GetHwndOf(win), VSCLASS_EDIT);
|
||||||
if (hTheme) {
|
if (hTheme) {
|
||||||
r.left = rect.x -1;
|
|
||||||
r.top = rect.y -1;
|
|
||||||
r.right = rect.x + rect.width + 1;
|
|
||||||
r.bottom = rect.y + rect.height + 1;
|
|
||||||
::DrawThemeBackground(
|
::DrawThemeBackground(
|
||||||
hTheme,
|
hTheme,
|
||||||
(HDC)dc.GetHDC(),
|
(HDC)dc.GetHDC(),
|
||||||
@@ -478,25 +485,34 @@ void draw_drop_down_arrow(Window* win, DC& dc, const wxRect& rect, bool active)
|
|||||||
, active ? wxCONTROL_PRESSED : 0);
|
, active ? wxCONTROL_PRESSED : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_checkbox(Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled) {
|
void draw_checkbox(const Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled) {
|
||||||
#if wxUSE_UXTHEME && defined(__WXMSW__)
|
#if defined(__WXMSW__)
|
||||||
// TODO: Windows version?
|
if (win == nullptr) win = dc.GetWindow();
|
||||||
#endif
|
#endif
|
||||||
// portable version
|
if (win) {
|
||||||
if (checked) {
|
wxRendererNative& rn = wxRendererNative::GetDefault();
|
||||||
dc.DrawCheckMark(wxRect(rect.x-1,rect.y-1,rect.width+2,rect.height+2));
|
rn.DrawCheckBox(const_cast<wxWindow*>(win), dc, rect, (checked ? wxCONTROL_CHECKED : 0) | (enabled ? 0 : wxCONTROL_DISABLED));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// portable version
|
||||||
|
if (checked) {
|
||||||
|
dc.DrawCheckMark(wxRect(rect.x+1,rect.y+1,rect.width-2,rect.height-2));
|
||||||
|
}
|
||||||
|
dc.SetPen(wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOWTEXT: wxSYS_COLOUR_GRAYTEXT));
|
||||||
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||||
|
dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
|
||||||
}
|
}
|
||||||
dc.SetPen(wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOWTEXT: wxSYS_COLOUR_GRAYTEXT));
|
|
||||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
||||||
dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_radiobox(Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled) {
|
void draw_radiobox(const Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled) {
|
||||||
#if wxUSE_UXTHEME && defined(__WXMSW__) && TODO_FIX_THEME_ENGINE
|
#if defined(__WXMSW__)
|
||||||
// TODO: Windows version?
|
if (win == nullptr) win = dc.GetWindow();
|
||||||
#endif
|
#endif
|
||||||
// portable version
|
if (win) {
|
||||||
#if 1
|
wxRendererNative& rn = wxRendererNative::GetDefault();
|
||||||
|
rn.DrawRadioBitmap(const_cast<wxWindow*>(win), dc, rect, (checked ? wxCONTROL_CHECKED : 0) | (enabled ? 0 : wxCONTROL_DISABLED));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
// circle drawing on windows looks absolutely horrible
|
// circle drawing on windows looks absolutely horrible
|
||||||
// so use rounded rectangles instead
|
// so use rounded rectangles instead
|
||||||
dc.SetPen(wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOWTEXT: wxSYS_COLOUR_GRAYTEXT));
|
dc.SetPen(wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOWTEXT: wxSYS_COLOUR_GRAYTEXT));
|
||||||
@@ -509,25 +525,14 @@ void draw_radiobox(Window* win, DC& dc, const wxRect& rect, bool checked, bool e
|
|||||||
//dc.DrawEllipse(rect.x+2,rect.y+2,rect.width-4,rect.height-4);
|
//dc.DrawEllipse(rect.x+2,rect.y+2,rect.width-4,rect.height-4);
|
||||||
dc.DrawRoundedRectangle(rect.x+3, rect.y+3, rect.width-6, rect.height-6, rect.width*0.5-4);
|
dc.DrawRoundedRectangle(rect.x+3, rect.y+3, rect.width-6, rect.height-6, rect.width*0.5-4);
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_selection_rectangle(Window* win, DC& dc, const wxRect& rect, bool selected, bool focused, bool hot) {
|
void draw_selection_rectangle(Window* win, DC& dc, const wxRect& rect, bool selected, bool focused, bool hot) {
|
||||||
#if wxUSE_UXTHEME && defined(__WXMSW__)
|
#if wxUSE_UXTHEME && defined(__WXMSW__)
|
||||||
#if !defined(NTDDI_LONGHORN) || NTDDI_VERSION < NTDDI_LONGHORN
|
HTHEME hTheme = (HTHEME)::OpenThemeData(GetHwndOf(win), VSCLASS_LISTVIEW);
|
||||||
#define LISS_NORMAL LIS_NORMAL
|
|
||||||
#define LISS_SELECTED LIS_SELECTED
|
|
||||||
#define LISS_SELECTEDNOTFOCUS LIS_SELECTEDNOTFOCUS
|
|
||||||
#define LISS_HOT LISS_NORMAL
|
|
||||||
#define LISS_HOTSELECTED LISS_SELECTED
|
|
||||||
#endif
|
|
||||||
HTHEME hTheme = (HTHEME)::OpenThemeData(GetHwndOf(win), L"LISTVIEW");
|
|
||||||
if (hTheme) {
|
if (hTheme) {
|
||||||
RECT r;
|
RECT r = msw_rect(rect);
|
||||||
r.left = rect.x;
|
|
||||||
r.top = rect.y;
|
|
||||||
r.right = rect.x + rect.width;
|
|
||||||
r.bottom = rect.y + rect.height;
|
|
||||||
::DrawThemeBackground(
|
::DrawThemeBackground(
|
||||||
hTheme,
|
hTheme,
|
||||||
(HDC)dc.GetHDC(),
|
(HDC)dc.GetHDC(),
|
||||||
|
|||||||
+2
-2
@@ -97,10 +97,10 @@ void draw_menu_arrow(Window* win, DC& dc, const wxRect& rect, bool active);
|
|||||||
void draw_drop_down_arrow(Window* win, DC& dc, const wxRect& rect, bool active);
|
void draw_drop_down_arrow(Window* win, DC& dc, const wxRect& rect, bool active);
|
||||||
|
|
||||||
/// Draws a check box
|
/// Draws a check box
|
||||||
void draw_checkbox(Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled = true);
|
void draw_checkbox(const Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled = true);
|
||||||
|
|
||||||
/// Draws a radio button
|
/// Draws a radio button
|
||||||
void draw_radiobox(Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled = true);
|
void draw_radiobox(const Window* win, DC& dc, const wxRect& rect, bool checked, bool enabled = true);
|
||||||
|
|
||||||
/// Draws a (fancy) selection rectangle
|
/// Draws a (fancy) selection rectangle
|
||||||
void draw_selection_rectangle(Window* win, DC& dc, const wxRect& rect, bool selected = true, bool focused = true, bool hot = false);
|
void draw_selection_rectangle(Window* win, DC& dc, const wxRect& rect, bool selected = true, bool focused = true, bool hot = false);
|
||||||
|
|||||||
+34
-58
@@ -14,10 +14,13 @@
|
|||||||
#include <script/image.hpp>
|
#include <script/image.hpp>
|
||||||
#include <wx/imaglist.h>
|
#include <wx/imaglist.h>
|
||||||
|
|
||||||
|
const int thumbnail_size = 18;
|
||||||
|
const double min_item_size = thumbnail_size;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ChoiceThumbnailRequest
|
// ----------------------------------------------------------------------------- : ChoiceThumbnailRequest
|
||||||
|
|
||||||
class ChoiceThumbnailRequest : public ThumbnailRequest {
|
class ChoiceThumbnailRequest : public ThumbnailRequest {
|
||||||
public:
|
public:
|
||||||
ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk, bool thread_safe);
|
ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk, bool thread_safe);
|
||||||
virtual Image generate();
|
virtual Image generate();
|
||||||
virtual void store(const Image&);
|
virtual void store(const Image&);
|
||||||
@@ -47,44 +50,16 @@ Image ChoiceThumbnailRequest::generate() {
|
|||||||
String name = canonical_name_form(s.field().choices->choiceName(id));
|
String name = canonical_name_form(s.field().choices->choiceName(id));
|
||||||
ScriptableImage& img = s.choice_images[name];
|
ScriptableImage& img = s.choice_images[name];
|
||||||
return img.isReady()
|
return img.isReady()
|
||||||
? img.generate(GeneratedImage::Options(16,16, &viewer().getStylePackage(), &viewer().getLocalPackage(), ASPECT_BORDER, true))
|
? img.generate(GeneratedImage::Options(thumbnail_size, thumbnail_size, &viewer().getStylePackage(), &viewer().getLocalPackage(), ASPECT_BORDER, true))
|
||||||
: wxImage();
|
: wxImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChoiceThumbnailRequest::store(const Image& img) {
|
void ChoiceThumbnailRequest::store(const Image& img) {
|
||||||
ChoiceStyle& s = style();
|
|
||||||
wxImageList* il = s.thumbnails;
|
|
||||||
while (id > il->GetImageCount()) {
|
|
||||||
il->Add(wxBitmap(16,16),*wxBLACK);
|
|
||||||
}
|
|
||||||
if (img.Ok()) {
|
if (img.Ok()) {
|
||||||
#ifdef __WXMSW__
|
ChoiceThumbnail& thumbnail = style().thumbnails[id];
|
||||||
// for some reason windows doesn't like completely transparent images if they do not have a mask
|
ChoiceThumbnailLock lock(thumbnail.mutex);
|
||||||
// HACK:
|
thumbnail.bitmap = img;
|
||||||
if (img.HasAlpha() && img.GetWidth() == 16 && img.GetHeight() == 16) {
|
thumbnail.status = THUMB_OK;
|
||||||
// is the image empty?
|
|
||||||
bool empty = true;
|
|
||||||
int* b = (int*)img.GetAlpha();
|
|
||||||
int* e = b + 16*16/sizeof(int);
|
|
||||||
while (b != e) {
|
|
||||||
if (*b++) {
|
|
||||||
empty = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if so, use a mask instead
|
|
||||||
if (empty) {
|
|
||||||
const_cast<Image&>(img).ConvertAlphaToMask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Hack ends here
|
|
||||||
#endif
|
|
||||||
if (id == il->GetImageCount()) {
|
|
||||||
il->Add(img);
|
|
||||||
} else {
|
|
||||||
il->Replace(id, img);
|
|
||||||
}
|
|
||||||
s.thumbnails_status[id] = THUMB_OK;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +71,9 @@ DropDownChoiceListBase::DropDownChoiceListBase
|
|||||||
, cve(cve)
|
, cve(cve)
|
||||||
, group(group)
|
, group(group)
|
||||||
{
|
{
|
||||||
icon_size.width = 16;
|
icon_size.width = min_item_size;
|
||||||
icon_size.height = 16;
|
icon_size.height = min_item_size;
|
||||||
item_size.height = max(16., item_size.height);
|
item_size.height = max(min_item_size, item_size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropDownChoiceListBase::onShow() {
|
void DropDownChoiceListBase::onShow() {
|
||||||
@@ -151,9 +126,6 @@ DropDownList* DropDownChoiceListBase::submenu(size_t item) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DropDownChoiceListBase::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
|
void DropDownChoiceListBase::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
|
||||||
// imagelist to use
|
|
||||||
wxImageList* il = style().thumbnails;
|
|
||||||
assert(il);
|
|
||||||
// find the image for the item
|
// find the image for the item
|
||||||
int image_id;
|
int image_id;
|
||||||
if (isFieldDefault(item)) {
|
if (isFieldDefault(item)) {
|
||||||
@@ -162,22 +134,21 @@ void DropDownChoiceListBase::drawIcon(DC& dc, int x, int y, size_t item, bool se
|
|||||||
image_id = getChoice(item)->first_id;
|
image_id = getChoice(item)->first_id;
|
||||||
}
|
}
|
||||||
// draw image
|
// draw image
|
||||||
if (image_id < il->GetImageCount()) {
|
if (image_id < style().thumbnails.size()) {
|
||||||
il->Draw(image_id, dc, x, y, itemEnabled(item) ? wxIMAGELIST_DRAW_NORMAL : wxIMAGELIST_DRAW_TRANSPARENT);
|
auto const& thumbnail = style().thumbnails[image_id];
|
||||||
|
if (thumbnail.status == THUMB_OK)
|
||||||
|
dc.DrawBitmap(thumbnail.bitmap, x, y);
|
||||||
|
//il->Draw(image_id, dc, x, y, itemEnabled(item) ? wxIMAGELIST_DRAW_NORMAL : wxIMAGELIST_DRAW_TRANSPARENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropDownChoiceListBase::generateThumbnailImages() {
|
void DropDownChoiceListBase::generateThumbnailImages() {
|
||||||
if (!isRoot()) return;
|
if (!isRoot()) return;
|
||||||
if (!style().thumbnails) {
|
|
||||||
style().thumbnails = new wxImageList(16,16);
|
|
||||||
}
|
|
||||||
int image_count = style().thumbnails->GetImageCount();
|
|
||||||
int end = group->lastId();
|
|
||||||
// init choice images
|
// init choice images
|
||||||
Context& ctx = cve.viewer.getContext();
|
Context& ctx = cve.viewer.getContext();
|
||||||
if (style().choice_images.empty() && style().image.isScripted()) {
|
if (style().choice_images.empty() && style().image.isScripted()) {
|
||||||
for (int i = 0 ; i < end ; ++i) {
|
int n = field().choices->lastId();
|
||||||
|
for (int i = 0 ; i < n; ++i) {
|
||||||
try {
|
try {
|
||||||
String name = canonical_name_form(field().choices->choiceName(i));
|
String name = canonical_name_form(field().choices->choiceName(i));
|
||||||
ctx.setVariable(_("input"), to_script(name));
|
ctx.setVariable(_("input"), to_script(name));
|
||||||
@@ -188,21 +159,26 @@ void DropDownChoiceListBase::generateThumbnailImages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// init thumbnail vector
|
||||||
|
if (style().thumbnails.empty()) {
|
||||||
|
style().thumbnails.resize(field().choices->lastId());
|
||||||
|
}
|
||||||
|
assert(style().thumbnails.size() == field().choices->lastId());
|
||||||
// request thumbnails
|
// request thumbnails
|
||||||
style().thumbnails_status.resize(end, THUMB_NOT_MADE);
|
int end = group->lastId();
|
||||||
for (int i = 0 ; i < end ; ++i) {
|
for (int i = group->first_id ; i < end ; ++i) {
|
||||||
ThumbnailStatus& status = style().thumbnails_status[i];
|
auto& thumbnail = style().thumbnails[i];
|
||||||
if (i >= image_count || status != THUMB_OK) {
|
ChoiceThumbnailLock lock(thumbnail.mutex);
|
||||||
|
if (thumbnail.status != THUMB_OK) {
|
||||||
// update image
|
// update image
|
||||||
ChoiceStyle& s = style();
|
String name = canonical_name_form(field().choices->choiceName(i));
|
||||||
String name = canonical_name_form(s.field().choices->choiceName(i));
|
ScriptableImage& img = style().choice_images[name];
|
||||||
ScriptableImage& img = s.choice_images[name];
|
if (!img.update(ctx) && thumbnail.status == THUMB_CHANGED) {
|
||||||
if (!img.update(ctx) && status == THUMB_CHANGED) {
|
thumbnail.status = THUMB_OK; // no need to rebuild
|
||||||
status = THUMB_OK; // no need to rebuild
|
|
||||||
} else if (img.isReady()) {
|
} else if (img.isReady()) {
|
||||||
// request this thumbnail
|
// request this thumbnail
|
||||||
thumbnail_thread.request(make_intrusive<ChoiceThumbnailRequest>(
|
thumbnail_thread.request(make_intrusive<ChoiceThumbnailRequest>(
|
||||||
&cve, i, status == THUMB_NOT_MADE && !img.local(), img.threadSafe()
|
&cve, i, thumbnail.status == THUMB_NOT_MADE && !img.local(), img.threadSafe()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -44,22 +44,22 @@ class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor {
|
|||||||
/// A drop down list of choices
|
/// A drop down list of choices
|
||||||
/** This is a base class, used for single and multiple choice fields */
|
/** This is a base class, used for single and multiple choice fields */
|
||||||
class DropDownChoiceListBase : public DropDownList {
|
class DropDownChoiceListBase : public DropDownList {
|
||||||
public:
|
public:
|
||||||
DropDownChoiceListBase(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group);
|
DropDownChoiceListBase(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onShow();
|
void onShow() override;
|
||||||
virtual size_t itemCount() const;
|
size_t itemCount() const override;
|
||||||
virtual bool lineBelow(size_t item) const;
|
bool lineBelow(size_t item) const override;
|
||||||
virtual bool itemEnabled(size_t item) const;
|
bool itemEnabled(size_t item) const override;
|
||||||
virtual String itemText(size_t item) const;
|
String itemText(size_t item) const override;
|
||||||
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const;
|
void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const override;
|
||||||
virtual DropDownList* submenu(size_t item) const;
|
DropDownList* submenu(size_t item) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const = 0;
|
virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_EVENT_TABLE();
|
DECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
ValueViewer& cve; ///< Editor this list belongs to
|
ValueViewer& cve; ///< Editor this list belongs to
|
||||||
|
|||||||
@@ -16,23 +16,23 @@
|
|||||||
|
|
||||||
/// A drop down list of color choices
|
/// A drop down list of color choices
|
||||||
class DropDownMultipleChoiceList : public DropDownChoiceListBase {
|
class DropDownMultipleChoiceList : public DropDownChoiceListBase {
|
||||||
public:
|
public:
|
||||||
DropDownMultipleChoiceList(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group);
|
DropDownMultipleChoiceList(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onShow();
|
void onShow() override;
|
||||||
virtual void select(size_t item);
|
void select(size_t item) override;
|
||||||
virtual size_t selection() const;
|
size_t selection() const override;
|
||||||
virtual bool stayOpen(size_t selection) const { return true; }
|
bool stayOpen(size_t selection) const override { return true; }
|
||||||
virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const;
|
DropDownList* createSubMenu(ChoiceField::ChoiceP group) const override;
|
||||||
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const;
|
void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
DropDownMultipleChoiceList::DropDownMultipleChoiceList
|
DropDownMultipleChoiceList::DropDownMultipleChoiceList
|
||||||
(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group)
|
(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group)
|
||||||
: DropDownChoiceListBase(parent, is_submenu, cve, group)
|
: DropDownChoiceListBase(parent, is_submenu, cve, group)
|
||||||
{
|
{
|
||||||
icon_size.width += 16;
|
icon_size.width += icon_size.height; // make room for checkbox
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropDownMultipleChoiceList::select(size_t item) {
|
void DropDownMultipleChoiceList::select(size_t item) {
|
||||||
@@ -59,17 +59,15 @@ void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, boo
|
|||||||
active = dynamic_cast<MultipleChoiceValueEditor&>(cve).value().value.isDefault();
|
active = dynamic_cast<MultipleChoiceValueEditor&>(cve).value().value.isDefault();
|
||||||
}
|
}
|
||||||
// draw checkbox
|
// draw checkbox
|
||||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
int size = (int)icon_size.height;
|
||||||
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
wxRect rect = RealRect(x+1,y+1,size-2,size-2);
|
||||||
dc.DrawRectangle(x,y,16,16);
|
|
||||||
wxRect rect = RealRect(x+2,y+2,12,12);
|
|
||||||
if (radio) {
|
if (radio) {
|
||||||
draw_radiobox(nullptr, dc, rect, active, itemEnabled(item));
|
draw_radiobox(this, dc, rect, active, itemEnabled(item));
|
||||||
} else {
|
} else {
|
||||||
draw_checkbox(nullptr, dc, rect, active, itemEnabled(item));
|
draw_checkbox(this, dc, rect, active, itemEnabled(item));
|
||||||
}
|
}
|
||||||
// draw icon
|
// draw icon
|
||||||
DropDownChoiceListBase::drawIcon(dc, x + 16, y, item, selected);
|
DropDownChoiceListBase::drawIcon(dc, x + size, y, item, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropDownMultipleChoiceList::onShow() {
|
void DropDownMultipleChoiceList::onShow() {
|
||||||
@@ -104,7 +102,7 @@ DropDownList& MultipleChoiceValueEditor::initDropDown() {
|
|||||||
void MultipleChoiceValueEditor::determineSize(bool force_fit) {
|
void MultipleChoiceValueEditor::determineSize(bool force_fit) {
|
||||||
if (!nativeLook()) return;
|
if (!nativeLook()) return;
|
||||||
// item height
|
// item height
|
||||||
item_height = 16;
|
item_height = 18;
|
||||||
// height depends on number of items and item height
|
// height depends on number of items and item height
|
||||||
int item_count = field().choices->lastId();
|
int item_count = field().choices->lastId();
|
||||||
style().height = item_count * item_height;
|
style().height = item_count * item_height;
|
||||||
|
|||||||
@@ -221,9 +221,9 @@ void DropDownWordList::drawIcon(DC& dc, int x, int y, size_t item, bool selected
|
|||||||
dc.DrawRectangle(x,y,16,16);
|
dc.DrawRectangle(x,y,16,16);
|
||||||
wxRect rect = RealRect(x+2,y+2,12,12);
|
wxRect rect = RealRect(x+2,y+2,12,12);
|
||||||
if (radio) {
|
if (radio) {
|
||||||
draw_radiobox(nullptr, dc, rect, items[item].active(), itemEnabled(item));
|
draw_radiobox(this, dc, rect, items[item].active(), itemEnabled(item));
|
||||||
} else {
|
} else {
|
||||||
draw_checkbox(nullptr, dc, rect, items[item].active(), itemEnabled(item));
|
draw_checkbox(this, dc, rect, items[item].active(), itemEnabled(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
|
|||||||
void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const String& choice, bool active) {
|
void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const String& choice, bool active) {
|
||||||
RealSize size; size.height = item_height;
|
RealSize size; size.height = item_height;
|
||||||
if (style().render_style & RENDER_CHECKLIST) {
|
if (style().render_style & RENDER_CHECKLIST) {
|
||||||
wxRect rect = dc.trRectToBB(RealRect(pos + RealSize(1,1), RealSize(12,12)));
|
wxRect rect = dc.trRectToBB(RealRect(pos + RealSize(1,1), RealSize(item_height-2, item_height-2)));
|
||||||
draw_checkbox(nullptr, dc.getDC(), rect, active); // TODO
|
draw_checkbox(nullptr, dc.getDC(), rect, active); // TODO
|
||||||
size = add_horizontal(size, RealSize(14,16));
|
size = add_horizontal(size, RealSize(item_height, item_height));
|
||||||
}
|
}
|
||||||
if (style().render_style & RENDER_IMAGE) {
|
if (style().render_style & RENDER_IMAGE) {
|
||||||
map<String,ScriptableImage>::iterator it = style().choice_images.find(canonical_name_form(choice));
|
map<String,ScriptableImage>::iterator it = style().choice_images.find(canonical_name_form(choice));
|
||||||
|
|||||||
Reference in New Issue
Block a user