1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "ColorTable.h"
21 
22 #include "View/ColorTableSelectedCommand.h"
23 
24 #include <wx/dcclient.h>
25 #include <wx/panel.h>
26 #include <wx/sizer.h>
27 
28 #include <algorithm>
29 #include <cassert>
30 
31 namespace TrenchBroom {
32     namespace View {
ColorTable(wxWindow * parent,wxWindowID winId,int cellSize,const wxPoint & pos,const wxSize & size,long style)33         ColorTable::ColorTable(wxWindow* parent, wxWindowID winId, int cellSize, const wxPoint& pos, const wxSize& size, long style) :
34         wxScrolledWindow(parent, winId, pos, size, (style & ~static_cast<long>(wxHSCROLL)) | static_cast<long>(wxVSCROLL)),
35         m_cellSize(cellSize),
36         m_margin(2) {
37             assert(m_cellSize > 0);
38 
39             Bind(wxEVT_SIZE, &ColorTable::OnSize, this);
40             Bind(wxEVT_PAINT, &ColorTable::OnPaint, this);
41             Bind(wxEVT_LEFT_UP, &ColorTable::OnMouseUp, this);
42 
43             SetScrollRate(0, m_cellSize + m_margin);
44         }
45 
setColors(const ColorList & colors)46         void ColorTable::setColors(const ColorList& colors) {
47             m_colors = colors;
48             m_selectedColors.clear();
49             updateVirtualSize();
50         }
51 
setSelection(const ColorList & colors)52         void ColorTable::setSelection(const ColorList& colors) {
53             m_selectedColors = colors;
54             Refresh();
55         }
56 
OnSize(wxSizeEvent & event)57         void ColorTable::OnSize(wxSizeEvent& event) {
58             if (IsBeingDeleted()) return;
59 
60             updateVirtualSize();
61         }
62 
OnPaint(wxPaintEvent & event)63         void ColorTable::OnPaint(wxPaintEvent& event) {
64             if (IsBeingDeleted()) return;
65 
66             const wxSize virtualSize = GetVirtualSize();
67             const int cols = computeCols(virtualSize.x);
68             const int rows = computeRows(cols);
69 
70             const wxPoint viewStart = GetViewStart();
71             int xRate, yRate;
72             GetScrollPixelsPerUnit(&xRate, &yRate);
73 
74             const int startX = -(viewStart.x * xRate) + m_margin;
75             int x = startX;
76             int y = -(viewStart.y * yRate) + m_margin;
77 
78             wxPaintDC dc(this);
79             dc.SetPen(*wxTRANSPARENT_PEN);
80             dc.SetBrush(*wxWHITE_BRUSH);
81             dc.DrawRectangle(0, 0, virtualSize.x, virtualSize.y);
82 
83             ColorList::const_iterator it = m_colors.begin();
84             for (int row = 0; row < rows; ++row) {
85                 for (int col = 0; col < cols; ++col) {
86                     if (it != m_colors.end()) {
87                         const wxColour& color = *it;
88 
89                         if (std::find(m_selectedColors.begin(), m_selectedColors.end(), color) != m_selectedColors.end()) {
90                             dc.SetPen(*wxRED_PEN);
91                             dc.SetBrush(*wxRED_BRUSH);
92                             dc.DrawRectangle(x-1, y-1, m_cellSize+2, m_cellSize+2);
93                         }
94 
95                         dc.SetPen(wxPen(color));
96                         dc.SetBrush(wxBrush(color));
97                         dc.DrawRectangle(x, y, m_cellSize, m_cellSize);
98 
99                         ++it;
100                     }
101                     x += m_cellSize + m_margin;
102                 }
103                 y += m_cellSize + m_margin;
104                 x = startX;
105             }
106         }
107 
OnMouseUp(wxMouseEvent & event)108         void ColorTable::OnMouseUp(wxMouseEvent& event) {
109             if (IsBeingDeleted()) return;
110 
111             const wxSize virtualSize = GetVirtualSize();
112             const int cols = computeCols(virtualSize.x);
113 
114             const wxPoint pos = CalcScrolledPosition(event.GetPosition());
115             const int col = (pos.x - m_margin) / (m_cellSize + m_margin);
116             const int row = (pos.y - m_margin) / (m_cellSize + m_margin);
117 
118             const size_t index = static_cast<size_t>(row * cols + col);
119             if (index < m_colors.size()) {
120                 const wxColor& color = m_colors[index];
121 
122                 ColorTableSelectedCommand command;
123                 command.setColor(color);
124                 command.SetEventObject(this);
125                 command.SetId(GetId());
126                 ProcessEvent(command);
127             }
128         }
129 
updateVirtualSize()130         void ColorTable::updateVirtualSize() {
131             int width = GetClientSize().x;
132             int cols = computeCols(width);
133             int rows = computeRows(cols);
134             int height = computeHeight(rows);
135             SetVirtualSize(width, height);
136 
137             if (GetClientSize().x != width) {
138                 width = GetClientSize().x;
139                 cols = computeCols(width);
140                 rows = computeRows(cols);
141                 height = computeHeight(rows);
142                 SetVirtualSize(width, height);
143                 assert(width == GetClientSize().x);
144             }
145         }
146 
computeCols(const int width) const147         int ColorTable::computeCols(const int width) const {
148             return (width - m_margin) / (m_cellSize + m_margin);
149         }
150 
computeRows(const int cols) const151         int ColorTable::computeRows(const int cols) const {
152             if (cols == 0)
153                 return 0;
154             return (static_cast<int>(m_colors.size()) + cols - 1) / cols;
155         }
156 
computeHeight(const int rows) const157         int ColorTable::computeHeight(const int rows) const {
158             return m_margin + rows * (m_cellSize + m_margin) - 1; // no idea why the -1 is necessary, but it is
159         }
160     }
161 }
162