2 * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
4 * ShapeFusion is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * ShapeFusion is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with ShapeFusion; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "BitmapBrowser.h"
20 #include "utilities.h"
22 DEFINE_EVENT_TYPE(wxEVT_BITMAPBROWSER)
23 DEFINE_EVENT_TYPE(wxEVT_BITMAPBROWSER_DELETE)
25 BEGIN_EVENT_TABLE(BitmapBrowser, wxScrolledWindow)
26 EVT_PAINT(BitmapBrowser::OnPaint)
27 EVT_SIZE(BitmapBrowser::OnSize)
28 EVT_LEFT_DOWN(BitmapBrowser::OnMouseDown)
29 EVT_RIGHT_DOWN(BitmapBrowser::OnMouseDown)
30 EVT_KEY_DOWN(BitmapBrowser::OnKeyDown)
33 BitmapBrowser::BitmapBrowser(wxWindow *parent, wxWindowID id):
34 wxScrolledWindow(parent, id, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxFULL_REPAINT_ON_RESIZE),
35 mColorTable(NULL), mSelection(-1), mNumCols(0), mNumRows(0), mFrozenCount(0)
37 SetBackgroundColour(wxColour(255, 255, 255));
38 mThumbnailPen.SetColour(200, 200, 200);
39 mSelectionPen.SetColour(0, 0, 0);
40 mSelectionPen.SetWidth(3);
44 mWhiteTransparency = true;
48 void BitmapBrowser::OnPaint(wxPaintEvent& e)
50 wxPaintDC tempdc(this);
54 GetClientSize(&cw, &ch);
55 CalcUnscrolledPosition(0, 0, &rx, &ry);
57 tempdc.SetPen(mThumbnailPen);
58 tempdc.SetBrush(*wxTRANSPARENT_BRUSH);
59 for (int i = 0; i < (int)mBitmaps.size(); i++) {
60 int x = mThumbnailPositions[i].x,
61 y = mThumbnailPositions[i].y;
63 if (y + mThumbnailSize < ry)
68 int bw = mThumbnails[i].GetWidth(),
69 bh = mThumbnails[i].GetHeight();
71 if (i == mSelection) {
72 tempdc.DrawBitmap(mThumbnails[i], x + mThumbnailSize/2 - bw/2, y + mThumbnailSize/2 - bh/2);
73 tempdc.SetPen(mSelectionPen);
74 tempdc.DrawRectangle(x-2, y-2, mThumbnailSize+4, mThumbnailSize+4);
75 tempdc.SetPen(mThumbnailPen);
77 tempdc.DrawRectangle(x-1, y-1, mThumbnailSize+2, mThumbnailSize+2);
78 tempdc.DrawBitmap(mThumbnails[i], x + mThumbnailSize/2 - bw/2, y + mThumbnailSize/2 - bh/2);
83 // widget resized, recalculate virtual size to correctly wrap thumbnails
84 void BitmapBrowser::OnSize(wxSizeEvent& e)
89 // handle clicks received by the widget
90 void BitmapBrowser::OnMouseDown(wxMouseEvent& e)
96 mouse = e.GetLogicalPosition(dc);
97 switch (e.GetButton()) {
98 case wxMOUSE_BTN_LEFT:
99 // handle bitmap selection
101 int new_selection = -1;
103 for (unsigned int i = 0; i < mThumbnailPositions.size(); i++) {
104 wxRect test(mThumbnailPositions[i].x, mThumbnailPositions[i].y, mThumbnailSize, mThumbnailSize);
106 if (test.Contains(mouse)) {
111 if (new_selection != mSelection) {
112 mSelection = new_selection;
115 // send selection event
116 wxCommandEvent event(wxEVT_BITMAPBROWSER, GetId());
118 event.SetEventObject(this);
119 event.SetInt(mSelection);
120 GetEventHandler()->ProcessEvent(event);
124 case wxMOUSE_BTN_RIGHT:
130 // handle keydown events
131 void BitmapBrowser::OnKeyDown(wxKeyEvent &e)
133 switch (e.GetKeyCode()) {
139 int new_selection = mSelection;
141 if (mSelection >= 0 && mSelection < (int)mBitmaps.size()) {
142 switch (e.GetKeyCode()) {
144 if (mSelection % mNumCols > 0)
148 if (mSelection % mNumCols < (mNumCols-1))
152 if (mSelection / mNumCols > 0)
153 new_selection -= mNumCols;
156 if (mSelection / mNumCols < (mNumRows-1))
157 new_selection += mNumCols;
160 } else if (mBitmaps.size() > 0) {
163 if (new_selection != mSelection && new_selection >= 0
164 && new_selection < (int)mBitmaps.size()) {
165 // TODO scroll to show the new selection
166 mSelection = new_selection;
169 // send bitmap selection event
170 wxCommandEvent event(wxEVT_BITMAPBROWSER, GetId());
172 event.SetEventObject(this);
173 event.SetInt(mSelection);
174 GetEventHandler()->ProcessEvent(event);
179 // send a bitmap delete event
180 if (mSelection >= 0 && mSelection < (int)mBitmaps.size()) {
181 wxCommandEvent event(wxEVT_BITMAPBROWSER_DELETE, GetId());
183 event.SetEventObject(this);
184 event.SetInt(mSelection);
185 GetEventHandler()->ProcessEvent(event);
194 // the Freeze()/Thaw() combo is necessary to get a reasonably
195 // responsive interface. Otherwise we would be doing bursts
196 // of UpdateVirtualSize() and potentially RebuildThumbnails()
197 // every time the user changes collection
198 void BitmapBrowser::Freeze(void)
203 void BitmapBrowser::Thaw(void)
205 if (mFrozenCount > 0) {
207 if (mFrozenCount == 0) {
214 int BitmapBrowser::GetSelection(void) const
219 // set the thumbnail size in pixels. Specify -1 to enable best-fit mode.
220 void BitmapBrowser::SetThumbnailSize(int size)
223 mThumbnailSize = size;
228 if (mFrozenCount == 0) {
236 void BitmapBrowser::SetTranspPixelsDisplay(bool show)
238 mWhiteTransparency = show;
239 if (mFrozenCount == 0) {
245 // add a new ShapesBitmap to the thumbnail list
246 void BitmapBrowser::AddBitmap(ShapesBitmap *bp)
249 if (bp->Pixels() != NULL) {
250 mBitmaps.push_back(bp);
251 mThumbnails.push_back(CreateThumbnail(bp));
252 if (mFrozenCount == 0) {
257 wxLogError(wxT("[BitmapBrowser] Added a bitmap with NULL pixels"));
262 // clear the thumbnail list
263 void BitmapBrowser::Clear(void)
267 mThumbnailPositions.clear();
270 if (mFrozenCount == 0)
274 // call before adding bitmaps!
275 void BitmapBrowser::SetColorTable(ShapesColorTable *ct)
278 if (mFrozenCount == 0) {
284 // calculate and set the wxWindow virtual size, based on the
285 // number of thumbnails, thumbnail dimensions and given visible
286 // size. Also pre-calculate thumbnail positions
287 void BitmapBrowser::UpdateVirtualSize(void)
290 unsigned int numbitmaps = mBitmaps.size();
293 GetClientSize(&width, &height);
294 if (numbitmaps < 1) {
295 SetVirtualSize(0, 0);
300 // calculate the best mThumbnailSize
301 // (maximum value not requiring window scrolling)
302 int max_bitmap_dimension = 10,
306 // find greatest dimension among all bitmaps
307 for (unsigned int i = 0; i < numbitmaps; i++) {
308 if (mBitmaps[i]->Width() > max_bitmap_dimension)
309 max_bitmap_dimension = mBitmaps[i]->Width();
310 if (mBitmaps[i]->Height() > max_bitmap_dimension)
311 max_bitmap_dimension = mBitmaps[i]->Height();
313 // FIXME a better algorithm, without looping?
314 for (new_tn_size = mMargin; ; new_tn_size++) {
315 int numcols = (width - mMargin) / (new_tn_size + mMargin),
316 numrows = (numcols > 0) ? (numbitmaps / numcols) : numbitmaps;
318 if (numrows * numcols < (int)numbitmaps)
320 int total_height = numrows * (new_tn_size + mMargin) + mMargin;
322 if (total_height > height || (new_tn_size + 2 * mMargin) > width) {
326 if (new_tn_size >= max_bitmap_dimension) {
327 // no point in wasting window space with huge
328 // thumbnails showing small bitmaps at their center
329 new_tn_size = max_bitmap_dimension;
333 if (new_tn_size != mThumbnailSize) {
334 mThumbnailSize = new_tn_size;
341 mNumCols = (width - mMargin) / (mThumbnailSize + mMargin);
342 mNumRows = (mNumCols > 0) ? (numbitmaps / mNumCols) : numbitmaps;
344 if (mNumRows * mNumCols < (int)numbitmaps)
347 SetVirtualSize(width, mNumRows * (mThumbnailSize + mMargin) + mMargin);
349 // recalculate thumbnail positions
353 mThumbnailPositions.clear();
354 for (unsigned int i = 0; i < numbitmaps; i++) {
355 mThumbnailPositions.push_back(wxPoint(x, y));
357 x += mThumbnailSize + mMargin;
358 if (x + mThumbnailSize + mMargin > width) {
360 y += mThumbnailSize + mMargin;
365 // transform a ShapesBitmap to a wxBitmap thumbnail
366 wxBitmap BitmapBrowser::CreateThumbnail(ShapesBitmap *bp)
371 newimg = ShapesBitmapToImage(bp, mColorTable, mWhiteTransparency);
372 return ImageThumbnail(newimg, mThumbnailSize, true);
375 void BitmapBrowser::RebuildThumbnail(unsigned int i)
377 if (i < mBitmaps.size())
378 mThumbnails[i] = CreateThumbnail(mBitmaps[i]);
381 // just re-decode the ShapesBitmaps to their thumbnail previews,
382 // without touching window sizes or thumbnail positions.
383 // Useful to update the display at the end of SetColorTable or after
384 // altering the ShapesBitmaps
385 void BitmapBrowser::RebuildThumbnails(void)
387 for (unsigned int i = 0; i < mBitmaps.size(); i++)
388 mThumbnails[i] = CreateThumbnail(mBitmaps[i]);