]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/html/m_image.cpp
Tries to fix wxListBox focus problems.
[wxWidgets.git] / src / html / m_image.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: m_image.cpp
3// Purpose: wxHtml module for displaying images
4// Author: Vaclav Slavik
5// RCS-ID: $Id$
6// Copyright: (c) 1999 Vaclav Slavik, Joel Lucsy
7// Licence: wxWindows Licence
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation
12#endif
13
14#include "wx/wxprec.h"
15
16#include "wx/defs.h"
17#if wxUSE_HTML && wxUSE_STREAMS
18
19#ifdef __BORDLANDC__
20#pragma hdrstop
21#endif
22
23#ifndef WXPRECOMP
24 #include "wx/dc.h"
25 #include "wx/scrolwin.h"
26 #include "wx/timer.h"
27 #include "wx/dcmemory.h"
28#endif
29
30#include "wx/html/forcelnk.h"
31#include "wx/html/m_templ.h"
32
33#include "wx/image.h"
34#include "wx/gifdecod.h"
35#include "wx/dynarray.h"
36
37#include <math.h>
38#include <float.h>
39
40FORCE_LINK_ME(m_image)
41
42
43
44
45WX_DECLARE_OBJARRAY(int, CoordArray);
46#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
47WX_DEFINE_OBJARRAY(CoordArray);
48
49
50//--------------------------------------------------------------------------------
51// wxHtmlImageMapAreaCell
52// 0-width, 0-height cell that represents single area in imagemap
53// (it's GetLink is called from wxHtmlImageCell's)
54//--------------------------------------------------------------------------------
55
56class wxHtmlImageMapAreaCell : public wxHtmlCell
57{
58 public:
59 enum celltype { CIRCLE, RECT, POLY };
60 protected:
61 CoordArray coords;
62 celltype type;
63 int radius;
64 public:
65 wxHtmlImageMapAreaCell( celltype t, wxString &coords, double pixel_scale = 1.0);
66 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
67};
68
69
70
71
72
73wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t, wxString &incoords, double pixel_scale )
74{
75 int i;
76 wxString x = incoords, y;
77
78 type = t;
79 while ((i = x.Find( ',' )) != -1)
80 {
81 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.Left( i ).c_str())) );
82 x = x.Mid( i + 1 );
83 }
84 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.c_str())) );
85}
86
87wxHtmlLinkInfo *wxHtmlImageMapAreaCell::GetLink( int x, int y ) const
88{
89 switch (type)
90 {
91 case RECT:
92 {
93 int l, t, r, b;
94
95 l = coords[ 0 ];
96 t = coords[ 1 ];
97 r = coords[ 2 ];
98 b = coords[ 3 ];
99 if (x >= l && x <= r && y >= t && y <= b)
100 {
101 return m_Link;
102 }
103 break;
104 }
105 case CIRCLE:
106 {
107 int l, t, r;
108 double d;
109
110 l = coords[ 0 ];
111 t = coords[ 1 ];
112 r = coords[ 2 ];
113 d = sqrt( (double) (((x - l) * (x - l)) + ((y - t) * (y - t))) );
114 if (d < (double)r)
115 {
116 return m_Link;
117 }
118 }
119 break;
120 case POLY:
121 {
122 if (coords.GetCount() >= 6)
123 {
124 int intersects = 0;
125 int wherex = x;
126 int wherey = y;
127 int totalv = coords.GetCount() / 2;
128 int totalc = totalv * 2;
129 int xval = coords[totalc - 2];
130 int yval = coords[totalc - 1];
131 int end = totalc;
132 int pointer = 1;
133
134 if ((yval >= wherey) != (coords[pointer] >= wherey))
135 {
136 if ((xval >= wherex) == (coords[0] >= wherex))
137 {
138 intersects += (xval >= wherex) ? 1 : 0;
139 }
140 else
141 {
142 intersects += ((xval - (yval - wherey) *
143 (coords[0] - xval) /
144 (coords[pointer] - yval)) >= wherex) ? 1 : 0;
145 }
146 }
147
148 while (pointer < end)
149 {
150 yval = coords[pointer];
151 pointer += 2;
152 if (yval >= wherey)
153 {
154 while ((pointer < end) && (coords[pointer] >= wherey))
155 {
156 pointer += 2;
157 }
158 if (pointer >= end)
159 {
160 break;
161 }
162 if ((coords[pointer - 3] >= wherex) ==
163 (coords[pointer - 1] >= wherex)) {
164 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
165 }
166 else
167 {
168 intersects +=
169 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
170 (coords[pointer - 1] - coords[pointer - 3]) /
171 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
172 }
173 }
174 else
175 {
176 while ((pointer < end) && (coords[pointer] < wherey))
177 {
178 pointer += 2;
179 }
180 if (pointer >= end)
181 {
182 break;
183 }
184 if ((coords[pointer - 3] >= wherex) ==
185 (coords[pointer - 1] >= wherex))
186 {
187 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
188 }
189 else
190 {
191 intersects +=
192 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
193 (coords[pointer - 1] - coords[pointer - 3]) /
194 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
195 }
196 }
197 }
198 if ((intersects & 1) != 0)
199 {
200 return m_Link;
201 }
202 }
203 }
204 break;
205 }
206
207 if (m_Next)
208 {
209 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
210 return a->GetLink( x, y );
211 }
212 return NULL;
213}
214
215
216
217
218
219
220
221
222//--------------------------------------------------------------------------------
223// wxHtmlImageMapCell
224// 0-width, 0-height cell that represents map from imagemaps
225// it is always placed before wxHtmlImageMapAreaCells
226// It responds to Find(wxHTML_COND_ISIMAGEMAP)
227//--------------------------------------------------------------------------------
228
229
230class wxHtmlImageMapCell : public wxHtmlCell
231{
232 public:
233 wxHtmlImageMapCell( wxString &name );
234 protected:
235 wxString m_Name;
236 public:
237 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
238 virtual const wxHtmlCell *Find( int cond, const void *param ) const;
239};
240
241
242wxHtmlImageMapCell::wxHtmlImageMapCell( wxString &name )
243{
244 m_Name = name ;
245}
246
247wxHtmlLinkInfo *wxHtmlImageMapCell::GetLink( int x, int y ) const
248{
249 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
250 if (a)
251 return a->GetLink( x, y );
252 return wxHtmlCell::GetLink( x, y );
253}
254
255const wxHtmlCell *wxHtmlImageMapCell::Find( int cond, const void *param ) const
256{
257 if (cond == wxHTML_COND_ISIMAGEMAP)
258 {
259 if (m_Name == *((wxString*)(param)))
260 return this;
261 }
262 return wxHtmlCell::Find(cond, param);
263}
264
265
266
267
268
269//--------------------------------------------------------------------------------
270// wxHtmlImageCell
271// Image/bitmap
272//--------------------------------------------------------------------------------
273
274class wxHtmlImageCell : public wxHtmlCell
275{
276public:
277 wxHtmlImageCell(wxWindow *window,
278 wxFSFile *input, int w = -1, int h = -1,
279 double scale = 1.0, int align = wxHTML_ALIGN_BOTTOM,
280 const wxString& mapname = wxEmptyString);
281 ~wxHtmlImageCell();
282 void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2);
283 virtual wxHtmlLinkInfo *GetLink(int x = 0, int y = 0) const;
284
285 void SetImage(const wxImage& img);
286#if wxUSE_GIF && wxUSE_TIMER
287 void AdvanceAnimation(wxTimer *timer);
288 virtual void Layout(int w);
289#endif
290
291private:
292 wxBitmap *m_bitmap;
293 int m_bmpW, m_bmpH;
294 wxScrolledWindow *m_window;
295#if wxUSE_GIF && wxUSE_TIMER
296 wxGIFDecoder *m_gifDecoder;
297 wxTimer *m_gifTimer;
298 int m_physX, m_physY;
299#endif
300 double m_scale;
301 wxHtmlImageMapCell *m_imageMap;
302 wxString m_mapName;
303};
304
305#if wxUSE_GIF && wxUSE_TIMER
306class wxGIFTimer : public wxTimer
307{
308 public:
309 wxGIFTimer(wxHtmlImageCell *cell) : m_cell(cell) {}
310 virtual void Notify()
311 {
312 m_cell->AdvanceAnimation(this);
313 }
314
315 private:
316 wxHtmlImageCell *m_cell;
317};
318#endif
319
320
321//--------------------------------------------------------------------------------
322// wxHtmlImageCell
323//--------------------------------------------------------------------------------
324
325wxHtmlImageCell::wxHtmlImageCell(wxWindow *window, wxFSFile *input,
326 int w, int h, double scale, int align,
327 const wxString& mapname) : wxHtmlCell()
328{
329 m_window = wxStaticCast(window, wxScrolledWindow);
330 m_scale = scale;
331 m_bitmap = NULL;
332 m_bmpW = w;
333 m_bmpH = h;
334 m_imageMap = NULL;
335 m_mapName = mapname;
336 SetCanLiveOnPagebreak(FALSE);
337#if wxUSE_GIF && wxUSE_TIMER
338 m_gifDecoder = NULL;
339 m_gifTimer = NULL;
340 m_physX = m_physY = -1;
341#endif
342
343 wxInputStream *s = input->GetStream();
344
345 if ( s )
346 {
347 bool readImg = TRUE;
348
349#if wxUSE_GIF && wxUSE_TIMER
350 if ( (input->GetLocation().Matches(wxT("*.gif")) ||
351 input->GetLocation().Matches(wxT("*.GIF"))) && m_window )
352 {
353 m_gifDecoder = new wxGIFDecoder(s, TRUE);
354 if ( m_gifDecoder->ReadGIF() == wxGIF_OK )
355 {
356 wxImage img;
357 if ( m_gifDecoder->ConvertToImage(&img) )
358 SetImage(img);
359
360 readImg = FALSE;
361
362 if ( m_gifDecoder->IsAnimation() )
363 {
364 m_gifTimer = new wxGIFTimer(this);
365 m_gifTimer->Start(m_gifDecoder->GetDelay(), TRUE);
366 }
367 else
368 {
369 wxDELETE(m_gifDecoder);
370 }
371 }
372 else
373 {
374 wxDELETE(m_gifDecoder);
375 }
376 }
377
378 if ( readImg )
379#endif
380 {
381 SetImage(wxImage(*s, wxBITMAP_TYPE_ANY));
382 }
383 }
384
385 m_Width = (int)(scale * (double)m_bmpW);
386 m_Height = (int)(scale * (double)m_bmpH);
387
388 switch (align)
389 {
390 case wxHTML_ALIGN_TOP :
391 m_Descent = m_Height;
392 break;
393 case wxHTML_ALIGN_CENTER :
394 m_Descent = m_Height / 2;
395 break;
396 case wxHTML_ALIGN_BOTTOM :
397 default :
398 m_Descent = 0;
399 break;
400 }
401 }
402
403void wxHtmlImageCell::SetImage(const wxImage& img)
404{
405 if ( img.Ok() )
406 {
407 delete m_bitmap;
408
409 int ww, hh;
410 ww = img.GetWidth();
411 hh = img.GetHeight();
412
413 if ( m_bmpW == -1 )
414 m_bmpW = ww;
415 if ( m_bmpH == -1 )
416 m_bmpH = hh;
417
418 if ((m_bmpW != ww) || (m_bmpH != hh))
419 {
420 wxImage img2 = img.Scale(m_bmpW, m_bmpH);
421 m_bitmap = new wxBitmap(img2);
422 }
423 else
424 m_bitmap = new wxBitmap(img);
425 }
426}
427
428#if wxUSE_GIF && wxUSE_TIMER
429void wxHtmlImageCell::AdvanceAnimation(wxTimer *timer)
430{
431 wxImage img;
432
433 m_gifDecoder->GoNextFrame(TRUE);
434
435 if ( m_physX == -1 )
436 {
437 m_physX = m_physY = 0;
438 for (wxHtmlCell *cell = this; cell; cell = cell->GetParent())
439 {
440 m_physX += cell->GetPosX();
441 m_physY += cell->GetPosY();
442 }
443 }
444
445 int x, y;
446 m_window->CalcScrolledPosition(m_physX, m_physY, &x, &y);
447 wxRect rect(x, y, m_Width, m_Height);
448
449 if ( m_window->GetClientRect().Intersects(rect) &&
450 m_gifDecoder->ConvertToImage(&img) )
451 {
452 if ( (int)m_gifDecoder->GetWidth() != m_Width ||
453 (int)m_gifDecoder->GetHeight() != m_Height ||
454 m_gifDecoder->GetLeft() != 0 || m_gifDecoder->GetTop() != 0 )
455 {
456 wxBitmap bmp(img);
457 wxMemoryDC dc;
458 dc.SelectObject(*m_bitmap);
459 dc.DrawBitmap(bmp, m_gifDecoder->GetLeft(), m_gifDecoder->GetTop());
460 }
461 else
462 SetImage(img);
463 m_window->Refresh(img.HasMask(), &rect);
464 }
465
466 timer->Start(m_gifDecoder->GetDelay(), TRUE);
467}
468
469void wxHtmlImageCell::Layout(int w)
470{
471 wxHtmlCell::Layout(w);
472 m_physX = m_physY = -1;
473}
474
475#endif
476
477wxHtmlImageCell::~wxHtmlImageCell()
478{
479 delete m_bitmap;
480#if wxUSE_GIF && wxUSE_TIMER
481 delete m_gifTimer;
482 delete m_gifDecoder;
483#endif
484}
485
486
487void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int WXUNUSED(view_y1), int WXUNUSED(view_y2))
488{
489 if (m_bitmap)
490 {
491 double us_x, us_y;
492 dc.GetUserScale(&us_x, &us_y);
493 dc.SetUserScale(us_x * m_scale, us_y * m_scale);
494
495 dc.DrawBitmap(*m_bitmap, (int) ((x + m_PosX) / m_scale),
496 (int) ((y + m_PosY) / m_scale), TRUE);
497 dc.SetUserScale(us_x, us_y);
498 }
499}
500
501wxHtmlLinkInfo *wxHtmlImageCell::GetLink( int x, int y ) const
502{
503 if (m_mapName.IsEmpty())
504 return wxHtmlCell::GetLink( x, y );
505 if (!m_imageMap)
506 {
507 wxHtmlContainerCell *p, *op;
508 op = p = GetParent();
509 while (p)
510 {
511 op = p;
512 p = p->GetParent();
513 }
514 p = op;
515 wxHtmlCell *cell = (wxHtmlCell*)p->Find(wxHTML_COND_ISIMAGEMAP,
516 (const void*)(&m_mapName));
517 if (!cell)
518 {
519 ((wxString&)m_mapName).Clear();
520 return wxHtmlCell::GetLink( x, y );
521 }
522 { // dirty hack, ask Joel why he fills m_ImageMap in this place
523 // THE problem is that we're in const method and we can't modify m_ImageMap
524 wxHtmlImageMapCell **cx = (wxHtmlImageMapCell**)(&m_imageMap);
525 *cx = (wxHtmlImageMapCell*)cell;
526 }
527 }
528 return m_imageMap->GetLink(x, y);
529}
530
531
532
533//--------------------------------------------------------------------------------
534// tag handler
535//--------------------------------------------------------------------------------
536
537TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
538
539 TAG_HANDLER_PROC(tag)
540 {
541 if (tag.GetName() == wxT("IMG"))
542 {
543 if (tag.HasParam(wxT("SRC")))
544 {
545 int w = -1, h = -1;
546 int al;
547 wxFSFile *str;
548 wxString tmp = tag.GetParam(wxT("SRC"));
549 wxString mn = wxEmptyString;
550
551 str = m_WParser->GetFS()->OpenFile(tmp);
552 if (tag.HasParam(wxT("WIDTH")))
553 tag.GetParamAsInt(wxT("WIDTH"), &w);
554 if (tag.HasParam(wxT("HEIGHT")))
555 tag.GetParamAsInt(wxT("HEIGHT"), &h);
556 al = wxHTML_ALIGN_BOTTOM;
557 if (tag.HasParam(wxT("ALIGN")))
558 {
559 wxString alstr = tag.GetParam(wxT("ALIGN"));
560 alstr.MakeUpper(); // for the case alignment was in ".."
561 if (alstr == wxT("TEXTTOP"))
562 al = wxHTML_ALIGN_TOP;
563 else if ((alstr == wxT("CENTER")) || (alstr == wxT("ABSCENTER")))
564 al = wxHTML_ALIGN_CENTER;
565 }
566 if (tag.HasParam(wxT("USEMAP")))
567 {
568 mn = tag.GetParam( wxT("USEMAP") );
569 if (mn.GetChar(0) == wxT('#'))
570 {
571 mn = mn.Mid( 1 );
572 }
573 }
574 wxHtmlImageCell *cel = NULL;
575 if (str)
576 {
577 cel = new wxHtmlImageCell(m_WParser->GetWindow(),
578 str, w, h,
579 m_WParser->GetPixelScale(),
580 al, mn);
581 cel->SetLink(m_WParser->GetLink());
582 cel->SetId(tag.GetParam(wxT("id"))); // may be empty
583 m_WParser->GetContainer()->InsertCell(cel);
584 delete str;
585 }
586 }
587 }
588 if (tag.GetName() == wxT("MAP"))
589 {
590 m_WParser->CloseContainer();
591 m_WParser->OpenContainer();
592 if (tag.HasParam(wxT("NAME")))
593 {
594 wxString tmp = tag.GetParam(wxT("NAME"));
595 wxHtmlImageMapCell *cel = new wxHtmlImageMapCell( tmp );
596 m_WParser->GetContainer()->InsertCell( cel );
597 }
598 ParseInner( tag );
599 m_WParser->CloseContainer();
600 m_WParser->OpenContainer();
601 }
602 if (tag.GetName() == wxT("AREA"))
603 {
604 if (tag.HasParam(wxT("SHAPE")))
605 {
606 wxString tmp = tag.GetParam(wxT("SHAPE"));
607 wxString coords = wxEmptyString;
608 tmp.MakeUpper();
609 wxHtmlImageMapAreaCell *cel = NULL;
610 if (tag.HasParam(wxT("COORDS")))
611 {
612 coords = tag.GetParam(wxT("COORDS"));
613 }
614 if (tmp == wxT("POLY"))
615 {
616 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY, coords, m_WParser->GetPixelScale() );
617 }
618 else if (tmp == wxT("CIRCLE"))
619 {
620 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE, coords, m_WParser->GetPixelScale() );
621 }
622 else if (tmp == wxT("RECT"))
623 {
624 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT, coords, m_WParser->GetPixelScale() );
625 }
626 if (cel != NULL && tag.HasParam(wxT("HREF")))
627 {
628 wxString tmp = tag.GetParam(wxT("HREF"));
629 wxString target = wxEmptyString;
630 if (tag.HasParam(wxT("TARGET"))) target = tag.GetParam(wxT("TARGET"));
631 cel->SetLink( wxHtmlLinkInfo(tmp, target));
632 }
633 if (cel != NULL) m_WParser->GetContainer()->InsertCell( cel );
634 }
635 }
636
637 return FALSE;
638 }
639
640TAG_HANDLER_END(IMG)
641
642
643
644TAGS_MODULE_BEGIN(Image)
645
646 TAGS_MODULE_ADD(IMG)
647
648TAGS_MODULE_END(Image)
649
650
651#endif