mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Added drop down list box, specialization for color editor; todo: proper positioning & sizing, redrawing the arrow button
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@91 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <data/field/color.hpp>
|
||||
#include <script/script.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(ColorField::ChoiceP);
|
||||
|
||||
@@ -23,6 +24,13 @@ String ColorField::typeName() const {
|
||||
return _("color");
|
||||
}
|
||||
|
||||
void ColorField::initDependencies(Context& ctx, const Dependency& dep) const {
|
||||
Field ::initDependencies(ctx, dep);
|
||||
script .initDependencies(ctx, dep);
|
||||
default_script.initDependencies(ctx, dep);
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_REFLECTION(ColorField) {
|
||||
REFLECT_BASE(Field);
|
||||
REFLECT(script);
|
||||
@@ -67,6 +75,11 @@ String ColorValue::toString() const {
|
||||
}
|
||||
return _("<color>");
|
||||
}
|
||||
bool ColorValue::update(Context& ctx) {
|
||||
Value::update(ctx);
|
||||
return field().default_script.invokeOnDefault(ctx, value)
|
||||
| field(). script.invokeOn(ctx, value);
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION_NAMELESS(ColorValue) {
|
||||
REFLECT_NAMELESS(value);
|
||||
|
||||
@@ -34,7 +34,9 @@ class ColorField : public Field {
|
||||
vector<ChoiceP> choices; ///< Color choices available
|
||||
bool allow_custom; ///< Are colors not in the list of choices allowed?
|
||||
String default_name; ///< Name of "default" value
|
||||
|
||||
|
||||
virtual void initDependencies(Context&, const Dependency&) const;
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
@@ -77,6 +79,7 @@ class ColorValue : public Value {
|
||||
Defaultable<Color> value; ///< The value
|
||||
|
||||
virtual String toString() const;
|
||||
virtual bool update(Context&);
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <gui/drop_down_list.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <render/value/viewer.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
#include <wx/dcbuffer.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownHider
|
||||
|
||||
// Class that intercepts all events not directed to a DropDownList, and closes the list
|
||||
class DropDownHider : public wxEvtHandler {
|
||||
public:
|
||||
DropDownHider(DropDownList& list) : list(list) {}
|
||||
|
||||
private:
|
||||
DropDownList& list;
|
||||
|
||||
virtual bool ProcessEvent(wxEvent& ev) {
|
||||
// close the list, and pass on the event
|
||||
// don't just use ev.Skip(), because this event handler will be removed by hiding,
|
||||
// so there will be no next handler to skip to
|
||||
wxEvtHandler* nh = GetNextHandler();
|
||||
list.hide(false);
|
||||
if (nh) nh->ProcessEvent(ev);
|
||||
}
|
||||
};
|
||||
|
||||
/*BEGIN_EVENT_TABLE(DropDownHider, wxEvtHandler)
|
||||
EVT_CUSTOM(wxEVT_LEFT_DOWN, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_RIGHT_DOWN, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_MOVE, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_SIZE, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_MENU_HIGHLIGHT, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_MENU, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_MENU_OPEN, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_ACTIVATE, wxID_ANY, DropDownHider::onEvent)
|
||||
// EVT_CUSTOM(wxEVT_CLOSE, wxID_ANY, DropDownHider::onEvent)
|
||||
EVT_CUSTOM(wxEVT_KILL_FOCUS, wxID_ANY, DropDownHider::onEvent)
|
||||
/* EVT_LEFT_DOWN ( (wxMouseEventFunction)&DropDownHider::onEvent)
|
||||
EVT_RIGHT_DOWN ( DropDownHider::onMouseEvent)
|
||||
EVT_MOVE ( DropDownHider::onMoveEvent)
|
||||
EVT_SIZE ( DropDownHider::onSizeEvent)
|
||||
EVT_MENU_HIGHLIGHT (wxID_ANY, DropDownHider::onMenuEvent)
|
||||
EVT_MENU (wxID_ANY, DropDownHider::onCommandEvent)
|
||||
EVT_MENU_OPEN ( DropDownHider::onMenuEvent)
|
||||
EVT_ACTIVATE ( DropDownHider::onActivateEvent)
|
||||
EVT_CLOSE ( DropDownHider::onCloseEvent)
|
||||
EVT_KILL_FOCUS ( DropDownHider::onFocusEvent)
|
||||
END_EVENT_TABLE ()
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownList : Show/Hide
|
||||
|
||||
DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer)
|
||||
: wxPopupWindow(parent)
|
||||
, mouse_down(false)
|
||||
, selected_item(NO_SELECTION)
|
||||
, open_sub_menu(nullptr)
|
||||
, parent_menu(is_submenu ? static_cast<DropDownList*>(GetParent()) : nullptr)
|
||||
, viewer(viewer)
|
||||
, item_size(100,1)
|
||||
{
|
||||
// determine item height
|
||||
wxClientDC dc(this);
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
int h;
|
||||
dc.GetTextExtent(_("X"), 0, &h);
|
||||
item_size.height = h;
|
||||
}
|
||||
|
||||
void DropDownList::show(bool in_place, wxPoint pos) {
|
||||
if (IsShown()) return;
|
||||
// find selection
|
||||
selected_item = selection();
|
||||
// fix size & position
|
||||
int line_count = 0;
|
||||
size_t count = itemCount();
|
||||
for (size_t i = 0 ; i < count ; ++i) if (lineBelow(i)) line_count += 1;
|
||||
wxSize size(
|
||||
item_size.width + marginW * 2,
|
||||
item_size.height * count + marginH * 2 + line_count
|
||||
);
|
||||
int parent_height = 0;
|
||||
/*if (!in_place) {
|
||||
// Position the drop down list below the editor control (based on the style)
|
||||
RotatedObject rot(editor.rotation);
|
||||
Rect r = rot.trNoNeg(style->rect);
|
||||
if (editor.nativeLook()) {
|
||||
pos = Point(r.left - 3, r.top - 3);
|
||||
size.width = max(size.width, r.width + 6);
|
||||
editorHeight = r.height + 6;
|
||||
} else {
|
||||
pos = Point(r.left - 1, r.top - 1);
|
||||
size.width = max(size.width, r.width + 2);
|
||||
editorHeight = r.height;
|
||||
}
|
||||
} else if (parent_menu) {
|
||||
parent_height = -item_height - 1;
|
||||
}
|
||||
*/
|
||||
// move & resize
|
||||
item_size.width = size.GetWidth() - marginW * 2;
|
||||
SetSize(size);
|
||||
Position(pos, wxSize(0, parent_height));
|
||||
// set event handler
|
||||
if (!parent_menu) {
|
||||
// Window* parent = wxGetTopLevelParent(this);
|
||||
// parent->PushEventHandler(&hider);
|
||||
}
|
||||
// show
|
||||
// oldSelectedItem = selectedItem;
|
||||
|
||||
if (selected_item == NO_SELECTION && itemCount() > 0) selected_item = 0; // select first item by default
|
||||
mouse_down = false;
|
||||
Window::Show();
|
||||
// fix drop down arrow
|
||||
redrawArrowOnParent();
|
||||
}
|
||||
|
||||
void DropDownList::hide(bool event) {
|
||||
// hide root
|
||||
DropDownList* root = this;
|
||||
while (root->parent_menu) {
|
||||
root = root->parent_menu;
|
||||
}
|
||||
root->realHide();
|
||||
// send event
|
||||
if (event && selected_item != NO_SELECTION) select(selected_item);
|
||||
}
|
||||
|
||||
void DropDownList::realHide() {
|
||||
if (!IsShown()) return;
|
||||
Window::Hide();
|
||||
// onHide();
|
||||
hideSubMenu();
|
||||
if (parent_menu) {
|
||||
parent_menu->open_sub_menu = 0;
|
||||
} else {
|
||||
// redrawDropDownArrowOnParent();
|
||||
// disconnect event handler
|
||||
// Window* parent = getTopLevelParent(&editor);
|
||||
// parent->RemoveEventHandler(&hider);
|
||||
}
|
||||
}
|
||||
|
||||
void DropDownList::hideSubMenu() {
|
||||
if (open_sub_menu) {
|
||||
open_sub_menu->realHide();
|
||||
open_sub_menu = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool DropDownList::showSubMenu() {
|
||||
if (selected_item == NO_SELECTION) {
|
||||
hideSubMenu();
|
||||
return false;
|
||||
} else {
|
||||
// find position to show item at
|
||||
return showSubMenu(selected_item, itemPosition(selected_item));
|
||||
}
|
||||
}
|
||||
bool DropDownList::showSubMenu(size_t item, int y) {
|
||||
DropDownList* sub_menu = item == NO_SELECTION ? nullptr : popup(item);
|
||||
if (sub_menu == open_sub_menu) return sub_menu; // no change
|
||||
hideSubMenu();
|
||||
open_sub_menu = sub_menu;
|
||||
if (!sub_menu) return false;
|
||||
// open new menu
|
||||
wxSize size = GetSize();
|
||||
sub_menu->show(true,
|
||||
sub_menu->GetParent()->ScreenToClient(ClientToScreen(
|
||||
wxPoint(size.GetWidth() - 1, y + item_size.height)
|
||||
)));
|
||||
return true;
|
||||
}
|
||||
|
||||
int DropDownList::itemPosition(size_t item) const {
|
||||
int y = marginH;
|
||||
size_t count = itemCount();
|
||||
for (size_t i = 0 ; i < count ; ++i) {
|
||||
if (i == item) return y;
|
||||
y += item_size.height + lineBelow(item);
|
||||
}
|
||||
// not found
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DropDownList::redrawArrowOnParent() {
|
||||
if (viewer) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownList : Drawing
|
||||
|
||||
void DropDownList::onPaint(wxPaintEvent&) {
|
||||
wxBufferedPaintDC dc(this);
|
||||
dc.BeginDrawing();
|
||||
draw(dc);
|
||||
dc.EndDrawing();
|
||||
}
|
||||
|
||||
void DropDownList::draw(DC& dc) {
|
||||
// Size
|
||||
wxSize cs = GetClientSize();
|
||||
// Draw background & frame
|
||||
dc.SetPen (wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWFRAME));
|
||||
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
dc.DrawRectangle(0, 0, cs.GetWidth(), cs.GetHeight());
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
// Draw items
|
||||
int y = marginH;
|
||||
size_t count = itemCount();
|
||||
for (size_t i = 0 ; i < count ; ++i) {
|
||||
drawItem(dc, y, i);
|
||||
y += item_size.height + lineBelow(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DropDownList::drawItem(DC& dc, int y, size_t item) {
|
||||
// draw background
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
if (item == selected_item) {
|
||||
dc.SetBrush (wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
|
||||
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
|
||||
dc.DrawRectangle(marginW, y, item_size.width, item_size.height);
|
||||
} else if (highlightItem(item)) {
|
||||
// mix a color between selection and window
|
||||
dc.SetBrush (lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),
|
||||
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW), 0.75));
|
||||
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
dc.DrawRectangle(marginW, y, item_size.width, item_size.height);
|
||||
} else {
|
||||
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
// draw text and icon
|
||||
drawIcon(dc, marginW, y, item, item == selected_item);
|
||||
dc.DrawText(capitalize(itemText(item)), marginW + icon_size.width, y + text_offset);
|
||||
// draw popup icon
|
||||
if (popup(item)) {
|
||||
draw_menu_arrow(this, dc, wxRect(marginW, y, item_size.width, item_size.height), item == selected_item);
|
||||
}
|
||||
// draw line below
|
||||
if (lineBelow(item)) {
|
||||
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
|
||||
dc.DrawLine(marginW, y + item_size.height, marginW + item_size.width, y + item_size.height);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownList : Events
|
||||
|
||||
void DropDownList::onLeftDown(wxMouseEvent&) {
|
||||
mouse_down = true; // prevent closing on mouseup of the click that opened the window
|
||||
}
|
||||
|
||||
void DropDownList::onLeftUp(wxMouseEvent&) {
|
||||
if (mouse_down) {
|
||||
// don't hide if there is a child menu
|
||||
if (selected_item != NO_SELECTION && popup(selected_item)) return;
|
||||
hide(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DropDownList::onMotion(wxMouseEvent& ev) {
|
||||
// size
|
||||
wxSize cs = GetClientSize();
|
||||
// find selected item
|
||||
if (ev.GetX() < marginW || ev.GetX() + marginW >= cs.GetWidth() || ev.GetY() < marginH || ev.GetY() + marginH >= cs.GetHeight()) return;
|
||||
int startY = marginH;
|
||||
size_t count = itemCount();
|
||||
for (size_t i = 0 ; i < count ; ++i) {
|
||||
int endY = startY + item_size.height;
|
||||
if (ev.GetY() >= startY && ev.GetY() < endY) {
|
||||
selected_item = i;
|
||||
showSubMenu(i, startY);
|
||||
Refresh(false);
|
||||
return;
|
||||
}
|
||||
startY = endY + lineBelow(i);
|
||||
}
|
||||
hideSubMenu();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownList : Parent events
|
||||
|
||||
void DropDownList::onMouseInParent(wxMouseEvent& ev, bool open_in_place) {
|
||||
if (IsShown()) hide(false);
|
||||
else show(open_in_place, wxPoint(ev.GetX(), ev.GetY()));
|
||||
}
|
||||
|
||||
void DropDownList::onCharInParent(wxKeyEvent& ev) {
|
||||
// keyboard codes
|
||||
int k = ev.GetKeyCode();
|
||||
if (IsShown()) {
|
||||
if (open_sub_menu) {
|
||||
// sub menu always takes keys
|
||||
open_sub_menu->onCharInParent(ev);
|
||||
} else {
|
||||
switch (k) {
|
||||
case WXK_UP:
|
||||
if (selected_item - 1 >= 0) {
|
||||
selected_item -= 1;
|
||||
Refresh(false);
|
||||
}
|
||||
break;
|
||||
case WXK_DOWN:
|
||||
if (selected_item + 1 < itemCount()) {
|
||||
selected_item += 1;
|
||||
Refresh(false);
|
||||
}
|
||||
break;
|
||||
case WXK_RETURN:
|
||||
if (!showSubMenu()) {
|
||||
hide(true);
|
||||
}
|
||||
break;
|
||||
case WXK_ESCAPE:
|
||||
hide(false);
|
||||
break;
|
||||
case WXK_LEFT:
|
||||
if (parent_menu) hide(false);
|
||||
break;
|
||||
default:
|
||||
// match first character of an item, start searching just after the current selection
|
||||
size_t si = selected_item != NO_SELECTION ? selected_item + 1 : 0;
|
||||
size_t count = itemCount();
|
||||
for (size_t i = si ; i < count + si ; ++i) {
|
||||
String c = itemText(i);
|
||||
if (!c.empty() && toUpper(c.GetChar(0)) == toUpper(ev.GetUnicodeKey())) {
|
||||
// first character matches
|
||||
selected_item = i;
|
||||
showSubMenu();
|
||||
Refresh(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (k==WXK_SPACE || k==WXK_RETURN || k==WXK_DOWN) {
|
||||
// drop down list is not shown yet, show it now
|
||||
show(false, wxPoint(0,0));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownList : Event table
|
||||
|
||||
// Note: some DropDownList events get sent to the parent which in turn should send them to the DropDownList
|
||||
BEGIN_EVENT_TABLE(DropDownList,wxPopupWindow)
|
||||
EVT_PAINT (DropDownList::onPaint)
|
||||
EVT_LEFT_DOWN (DropDownList::onLeftDown)
|
||||
EVT_LEFT_UP (DropDownList::onLeftUp)
|
||||
EVT_MOTION (DropDownList::onMotion)
|
||||
END_EVENT_TABLE ()
|
||||
@@ -0,0 +1,107 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#ifndef HEADER_GUI_DROP_DOWN_LIST
|
||||
#define HEADER_GUI_DROP_DOWN_LIST
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/rotation.hpp>
|
||||
#include <wx/popupwin.h> // undocumented: wxPopupWindow
|
||||
|
||||
class ValueViewer;
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownList
|
||||
|
||||
/// A popup/drop down window displaying a list of items
|
||||
/** This class is an abstract base for various drop down lists */
|
||||
class DropDownList : public wxPopupWindow {
|
||||
public:
|
||||
/// Create a drop down list, possibly a sub menu
|
||||
/** the viewer will be notified to redraw its drop down icon */
|
||||
DropDownList(Window* parent, bool is_submenu = false, ValueViewer* viewer = nullptr);
|
||||
|
||||
/// Show the editor
|
||||
/** if in_place, then shows the list at the position pos */
|
||||
void show(bool in_place, wxPoint pos);
|
||||
/// Close the list, optionally send an onSelect event
|
||||
void hide(bool event);
|
||||
|
||||
// --------------------------------------------------- : Parent control
|
||||
/// Takes all keyboard events from a FieldEditor
|
||||
void onCharInParent(wxKeyEvent&);
|
||||
/// Takes a mouse event from the parent, show/hide as appropriate
|
||||
void onMouseInParent(wxMouseEvent&, bool open_in_place);
|
||||
|
||||
protected:
|
||||
// --------------------------------------------------- : Selection
|
||||
static const size_t NO_SELECTION = (size_t)-1;
|
||||
|
||||
/// Signal that the list is closed and something is selected
|
||||
virtual void select(size_t selection) = 0;
|
||||
/// When the list is being opened, what should be selected?
|
||||
virtual size_t selection() const = 0;
|
||||
|
||||
// --------------------------------------------------- : Item information
|
||||
/// Number of items
|
||||
virtual size_t itemCount() const = 0;
|
||||
/// Text of an item
|
||||
virtual String itemText(size_t item) const = 0;
|
||||
/// Draw an icon at the specified location
|
||||
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const = 0;
|
||||
/// Is there a line below an item?
|
||||
virtual bool lineBelow(size_t item) const { return false; }
|
||||
/// Should the item be highlighted?
|
||||
virtual bool highlightItem(size_t item) const { return false; }
|
||||
// An extra menu that pops up from an item, or null if there is no popup menu
|
||||
virtual DropDownList* popup(size_t item) const { return nullptr; }
|
||||
|
||||
// --------------------------------------------------- : Layout
|
||||
|
||||
static const int marginW = 1;
|
||||
static const int marginH = 1;
|
||||
|
||||
// may be changed by derived class
|
||||
int text_offset; ///< Vertical distance between top of item and text
|
||||
RealSize item_size; ///< Size of an item;
|
||||
RealSize icon_size; ///< Size of icons;
|
||||
|
||||
private:
|
||||
// --------------------------------------------------- : Data
|
||||
|
||||
size_t selected_item; ///< The item that is selected, or NO_SELECTION
|
||||
bool mouse_down; ///< Is the mouse pressed?
|
||||
DropDownList* open_sub_menu; ///< The sub menu that is currently shown, if any
|
||||
DropDownList* parent_menu; ///< The parent menu, only applies to sub menus
|
||||
ValueViewer* viewer; ///< The parent viewer object (optional)
|
||||
|
||||
// --------------------------------------------------- : Events
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
void onPaint(wxPaintEvent&);
|
||||
void onLeftDown(wxMouseEvent&);
|
||||
void onLeftUp (wxMouseEvent&);
|
||||
void onMotion (wxMouseEvent&);
|
||||
|
||||
// --------------------------------------------------- : Privates
|
||||
|
||||
/// Return the y coordinate of an item
|
||||
int itemPosition(size_t item) const;
|
||||
|
||||
void realHide();
|
||||
void hideSubMenu();
|
||||
bool showSubMenu();
|
||||
bool showSubMenu(size_t item, int y);
|
||||
|
||||
void draw(DC& dc);
|
||||
void drawItem(DC& dc, int y, size_t item);
|
||||
|
||||
void redrawArrowOnParent();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <util/error.hpp>
|
||||
#include <util/rotation.hpp>
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/renderer.h>
|
||||
|
||||
#if wxUSE_UXTHEME
|
||||
#include <wx/msw/uxtheme.h>
|
||||
@@ -138,3 +139,23 @@ void draw_control_border(Window* win, DC& dc, const wxRect& rect) {
|
||||
draw3DBorder(dc, rect.x - 1, rect.y - 1, rect.x + rect.width, rect.y + rect.height);
|
||||
#endif
|
||||
}
|
||||
|
||||
// portable, based on wxRendererGeneric::DrawComboBoxDropButton
|
||||
void draw_menu_arrow(Window* win, DC& dc, const wxRect& rect, bool active) {
|
||||
wxPoint pt[] =
|
||||
{ wxPoint(0, 0)
|
||||
, wxPoint(4, 4)
|
||||
, wxPoint(0, 8)
|
||||
};
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(wxSystemSettings::GetColour(active ? wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT));
|
||||
dc.DrawPolygon(3, pt, rect.x + rect.width - 6, rect.y + (rect.height - 9) / 2);
|
||||
}
|
||||
|
||||
void draw_drop_down_arrow(Window* win, DC& dc, const wxRect& rect, bool active) {
|
||||
wxRendererNative& rn = wxRendererNative::GetDefault();
|
||||
int w = wxSystemSettings::GetMetric(wxSYS_VSCROLL_ARROW_X); // drop down arrow is same size
|
||||
rn.DrawComboBoxDropButton(win, dc,
|
||||
wxRect(rect.x + rect.width - w, rect.y, w, rect.height)
|
||||
, active ? wxCONTROL_PRESSED : 0);
|
||||
}
|
||||
|
||||
@@ -45,5 +45,10 @@ Image load_resource_image(const String& name);
|
||||
/** Based on wxRendererXP::DrawComboBoxDropButton */
|
||||
void draw_control_border(Window* win, DC& dc, const wxRect& rect);
|
||||
|
||||
/// Draws an arrow for a menu item indicating it has a sub menu
|
||||
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);
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
#include <gui/value/choice.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(Choice) {}
|
||||
|
||||
+139
-1
@@ -7,5 +7,143 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <gui/value/color.hpp>
|
||||
#include <gui/drop_down_list.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <wx/colordlg.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
DECLARE_TYPEOF_COLLECTION(ColorField::ChoiceP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownColorList
|
||||
|
||||
// A drop down list of color choices
|
||||
class DropDownColorList : public DropDownList {
|
||||
public:
|
||||
DropDownColorList(Window* parent, ColorValueEditor& cve);
|
||||
|
||||
protected:
|
||||
virtual size_t itemCount() const;
|
||||
virtual bool lineBelow(size_t item) const;
|
||||
virtual String itemText(size_t item) const;
|
||||
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const;
|
||||
|
||||
virtual void select(size_t item);
|
||||
virtual size_t selection() const;
|
||||
|
||||
private:
|
||||
ColorValueEditor& cve;
|
||||
mutable Color default_color;
|
||||
|
||||
inline const ColorField& field() const { return cve.field(); }
|
||||
// // default, custom item
|
||||
bool hasDefault() const { return field().default_script; }
|
||||
bool hasCustom() const { return field().allow_custom; }
|
||||
};
|
||||
|
||||
|
||||
DropDownColorList::DropDownColorList(Window* parent, ColorValueEditor& cve)
|
||||
: DropDownList(parent, false, &cve)
|
||||
, cve(cve)
|
||||
{
|
||||
icon_size.width = 25;
|
||||
if (item_size.height < 16) {
|
||||
text_offset = (16 - item_size.height) / 2;
|
||||
item_size.height = 16;
|
||||
}
|
||||
}
|
||||
|
||||
size_t DropDownColorList::itemCount() const {
|
||||
return cve.field().choices.size() + hasDefault() + hasCustom();
|
||||
}
|
||||
bool DropDownColorList::lineBelow(size_t item) const {
|
||||
return (item == 0 && hasDefault()) // below default item
|
||||
|| (item == itemCount() - 2 && hasCustom()); // above custom item
|
||||
}
|
||||
String DropDownColorList::itemText(size_t item) const {
|
||||
if (item == 0 && hasDefault()) {
|
||||
return field().default_name;
|
||||
} else if (item == itemCount()-1 && hasCustom()) {
|
||||
return _("Custom...");
|
||||
} else {
|
||||
return field().choices[item - hasDefault()]->name;
|
||||
}
|
||||
}
|
||||
|
||||
void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
|
||||
Color col;
|
||||
if (item == 0 && hasDefault()) { // default
|
||||
col = default_color;
|
||||
} else if (item == itemCount()-1 && hasCustom()) { // custom color
|
||||
col = cve.value().value();
|
||||
} else {
|
||||
col = field().choices[item - hasDefault()]->color;
|
||||
}
|
||||
// draw a rectangle with the right color
|
||||
dc.SetPen(wxSystemSettings::GetColour(selected ? wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT));
|
||||
dc.SetBrush(col);
|
||||
dc.DrawRectangle(x+1, y+1, icon_size.width-2, item_size.height-2);
|
||||
}
|
||||
|
||||
size_t DropDownColorList::selection() const {
|
||||
// find selected color
|
||||
size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION;
|
||||
size_t i = 0;
|
||||
FOR_EACH_CONST(c, field().choices) {
|
||||
if (c->color == cve.value().value()) {
|
||||
selection = i + hasDefault();
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// has default item?
|
||||
if (hasDefault() && cve.value().value.isDefault()) {
|
||||
// default is selected
|
||||
default_color = cve.value().value();
|
||||
return 0;
|
||||
} else if (hasDefault()) {
|
||||
// evaluate script to find default color
|
||||
default_color = *field().default_script.invoke(cve.viewer.getContext());
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
void DropDownColorList::select(size_t item) {
|
||||
if (item == 0 && hasDefault()) {
|
||||
cve.change( Defaultable<Color>());
|
||||
} else if (item == itemCount() - 1 && hasCustom()) {
|
||||
cve.changeCustom();
|
||||
} else {
|
||||
cve.change(field().choices[item - hasDefault()]->color);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ColorValueEditor
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(Color)
|
||||
, drop_down(new DropDownColorList(&editor(), *this))
|
||||
{}
|
||||
|
||||
void ColorValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
|
||||
drop_down->onMouseInParent(ev, !nativeLook());
|
||||
}
|
||||
void ColorValueEditor::onChar(wxKeyEvent& ev) {
|
||||
drop_down->onCharInParent(ev);
|
||||
}
|
||||
void ColorValueEditor::onLoseFocus() {
|
||||
drop_down->hide(false);
|
||||
}
|
||||
|
||||
void ColorValueEditor::drawSelection(RotatedDC& dc) {
|
||||
if (nativeLook()) {
|
||||
draw_drop_down_arrow(&editor(), dc.getDC(), style().getRect().grow(1), drop_down->IsShown());
|
||||
}
|
||||
}
|
||||
void ColorValueEditor::determineSize() {
|
||||
style().height = 20;
|
||||
}
|
||||
|
||||
void ColorValueEditor::change(const Defaultable<Color>& c) {
|
||||
// getSet().actions.add(new ColorChangeAction(value(), c));
|
||||
}
|
||||
void ColorValueEditor::changeCustom() {
|
||||
Color c = wxGetColourFromUser(0, value().value());
|
||||
if (c.Ok()) change(c);
|
||||
}
|
||||
|
||||
@@ -13,12 +13,30 @@
|
||||
#include <gui/value/editor.hpp>
|
||||
#include <render/value/color.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(DropDownList);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ColorValueEditor
|
||||
|
||||
/// An editor 'control' for editing ColorValues
|
||||
class ColorValueEditor : public ColorValueViewer, public ValueEditor {
|
||||
public:
|
||||
DECLARE_VALUE_EDITOR(Color);
|
||||
|
||||
// --------------------------------------------------- : Events
|
||||
virtual void onLeftDown(const RealPoint& pos, wxMouseEvent& ev);
|
||||
virtual void onChar(wxKeyEvent& ev);
|
||||
virtual void onLoseFocus();
|
||||
|
||||
virtual void drawSelection(RotatedDC& dc);
|
||||
virtual void determineSize();
|
||||
|
||||
private:
|
||||
DropDownListP drop_down;
|
||||
friend class DropDownColorList;
|
||||
/// Change the color
|
||||
void change(const Defaultable<Color>& c);
|
||||
/// Change to a custom color
|
||||
void changeCustom();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
@@ -109,9 +109,7 @@ class ValueEditor {
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
#define DECLARE_VALUE_EDITOR(Type) \
|
||||
Type##ValueEditor(DataEditor& parent, const Type##StyleP& style) \
|
||||
: Type##ValueViewer(parent, style) \
|
||||
{} \
|
||||
Type##ValueEditor(DataEditor& parent, const Type##StyleP& style); \
|
||||
virtual ValueEditor* getEditor() { return this; } \
|
||||
private: \
|
||||
inline DataEditor& editor() const { \
|
||||
@@ -119,5 +117,9 @@ class ValueEditor {
|
||||
} \
|
||||
public:
|
||||
|
||||
#define IMPLEMENT_VALUE_EDITOR(Type) \
|
||||
Type##ValueEditor::Type##ValueEditor(DataEditor& parent, const Type##StyleP& style) \
|
||||
: Type##ValueViewer(parent, style)
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
#include <gui/value/image.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(Image) {}
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
#include <gui/value/multiple_choice.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(MultipleChoice) {}
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
#include <gui/value/symbol.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(Symbol) {}
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
#include <gui/value/text.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(Text) {}
|
||||
|
||||
@@ -574,6 +574,12 @@
|
||||
<File
|
||||
RelativePath=".\gui\about_window.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gui\drop_down_list.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gui\drop_down_list.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gui\new_window.cpp">
|
||||
</File>
|
||||
|
||||
@@ -20,6 +20,7 @@ void store(const ScriptValueP& val, double& var) { var = *val; }
|
||||
void store(const ScriptValueP& val, bool& var) { var = static_cast<int>(*val); }
|
||||
void store(const ScriptValueP& val, Color& var) { var = *val; }
|
||||
void store(const ScriptValueP& val, Defaultable<String>& var) { var.assign(*val); }
|
||||
void store(const ScriptValueP& val, Defaultable<Color>& var) { var.assign(*val); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : OptionalScript
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ void store(const ScriptValueP& val, double& var);
|
||||
void store(const ScriptValueP& val, bool& var);
|
||||
void store(const ScriptValueP& val, Color& var);
|
||||
void store(const ScriptValueP& val, Defaultable<String>& var);
|
||||
void store(const ScriptValueP& val, Defaultable<Color>& var);
|
||||
|
||||
// ----------------------------------------------------------------------------- : OptionalScript
|
||||
|
||||
|
||||
Reference in New Issue
Block a user