///////////////////////////////////////////////////////////////////////////// // Name: card.cpp // tag: A class to draw and manipulate a card. // Author: Chris Breeze // Modified by: David Roundy // Created: 21/07/97 // Copyright: (c) 1993-1998 Chris Breeze, 2001 David Roundy // Licence: GPL /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ ///////////////////////////////////////////////////////////////////////////// //+-------------------------------------------------------------+ //| Description //| A class for drawing playing cards. //| Currently assumes that the card symbols have been //| loaded into hbmap_symbols and the pictures for the //| Jack, Queen and King have been loaded into //| hbmap_pictures. //+-------------------------------------------------------------+ // For compilers that support precompilation, includes . #include #ifndef WX_PRECOMP #include #include #endif #include #include #include #include "colors.h" #include "card.h" #include "suit.h" #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) #include "pictures.xpm" #endif #include "symbols.xbm" #include "debug.h" wxBitmap* Card::m_pictureBmap = 0; wxBitmap* Card::m_symbolBmap = 0; BEGIN_EVENT_TABLE(wxCard, wxControl) EVT_PAINT (wxCard::DoPaint) END_EVENT_TABLE() static inline Suit value_to_suit(int value) { switch ((value - 1) / 13) { case 0: return clubs; case 1: return diamonds; case 2: return hearts; case 3: return spades; } } static inline SuitColour suit_to_color(Suit suit) { switch (suit) { case clubs: case spades: return black; case diamonds: case hearts: return red; } } wxCard::wxCard(wxWindow* parent, int value, WayUp way_up, const wxPoint& pos, const wxSize& size) : wxControl(parent, -1, pos, size) { SetBackgroundColour( aBridgeBackgroundColour() ); m_card = Card(value, way_up); } wxCard::wxCard(wxWindow* parent, const Card &ca, const wxPoint& pos, const wxSize& size) : wxControl(parent, -1, pos, size) { SetBackgroundColour( aBridgeBackgroundColour() ); m_card = ca; } wxCard::~wxCard() { } Card::Card(int value, WayUp way_up) { next = NULL; m_wayUp = way_up; if (!m_symbolBmap) { m_symbolBmap = new wxBitmap(Symbols_bits, Symbols_width, Symbols_height); if (!m_symbolBmap->Ok()) { ::wxMessageBox("Failed to load bitmap CardSymbols", "Error"); } } if (!m_pictureBmap) { #ifdef __WXMSW__ m_pictureBmap = new wxBitmap("CardPictures", wxBITMAP_TYPE_BMP_RESOURCE); #else m_pictureBmap = new wxBitmap(Pictures); #endif if (!m_pictureBmap->Ok()) { ::wxMessageBox("Failed to load bitmap CardPictures", "Error"); } } if (value >= 1 && value <= PackSize) { m_suit = value_to_suit(value); m_colour = suit_to_color(m_suit); m_pipValue = 1 + (value - 1) % 13; m_status = TRUE; } else { m_status = FALSE; } cached_w = cached_h = 0; cachedbits = NULL; } Card::Card(wxString str, WayUp way_up) { next = NULL; m_wayUp = way_up; if (!m_symbolBmap) { m_symbolBmap = new wxBitmap(Symbols_bits, Symbols_width, Symbols_height); if (!m_symbolBmap->Ok()) { ::wxMessageBox("Failed to load bitmap CardSymbols", "Error"); } } if (!m_pictureBmap) { #ifdef __WXMSW__ m_pictureBmap = new wxBitmap("CardPictures", wxBITMAP_TYPE_BMP_RESOURCE); #else m_pictureBmap = new wxBitmap(Pictures); #endif if (!m_pictureBmap->Ok()) { ::wxMessageBox("Failed to load bitmap CardPictures", "Error"); } } m_pipValue=1; m_suit = clubs; if (sscanf(str.c_str(), "%d,%d", &m_pipValue, (int *)&m_suit) != 2) { wxBell(); DebugMsg("Bad string input for a card: " + str); m_status = FALSE; } else { if (m_pipValue == 14) m_pipValue = 1; switch (m_suit) { case clubs: case spades: m_colour = black; break; case hearts: case diamonds: m_colour = red; break; } m_status = TRUE; } cached_w = cached_h = 0; cachedbits = NULL; } Card::Card(const Card &c) { next = c.next; SetSameAs(c); } wxString Card::GetString() const { wxString out(""); out << (int)GetBridgeValue(); out << wxString(",") << (int)m_suit; return out; } //+-------------------------------------------------------------+ //| Card::~Card() | //+-------------------------------------------------------------+ //| Description: | //| Destructor - nothing to do at present. | //+-------------------------------------------------------------+ Card::~Card() { delete cachedbits; } void Card::SetSameAs(const Card &c) { m_suit = c.m_suit; m_colour = c.m_colour; m_pipValue = c.m_pipValue; m_status = c.m_status; m_wayUp = c.m_wayUp; cached_w = c.cached_w; cached_h = c.cached_h; if (c.cachedbits) cachedbits = new wxBitmap(*c.cachedbits); else cachedbits = NULL; } //+-------------------------------------------------------------+ //| Card::Draw() | //+-------------------------------------------------------------+ //| Description: | //| Draw the card at (x, y). | //| If the card is facedown draw the back of the card. | //| If the card is faceup draw the front of the card. | //| Cards are not held in bitmaps, instead they are drawn | //| from their constituent parts when required. | //| hbmap_symbols contains large and small suit symbols and | //| pip values. These are copied to the appropriate part of | //| the card. Picture cards use the pictures defined in | //| hbmap_pictures. Note that only one picture is defined | //| for the Jack, Queen and King, unlike a real pack where | //| each suit is different. | //| | //| WARNING: | //| The locations of these symbols is 'hard-wired' into the | //| code. Editing the bitmaps or the numbers below will | //| result in the wrong symbols being displayed. | //+-------------------------------------------------------------+ void wxCard::DoPaint(wxPaintEvent& event) { wxPaintDC dc(this); int CardWidth, CardHeight; GetSize(&CardWidth, &CardHeight); m_card.Draw(dc,0,0,CardWidth,CardHeight); } void Card::TurnCard(WayUp way_up) { m_wayUp = way_up; } void Card::Draw(wxDC& outdc, int x, int y, int CardWidth, int CardHeight) { if (CardHeight != cached_h || CardWidth != cached_w) { cached_w = CardWidth; cached_h = CardHeight; delete cachedbits; cachedbits = new wxBitmap(CardWidth, CardHeight, -1); wxMemoryDC dc; dc.SelectObject( *cachedbits ); dc.SetBackground( aBridgeBackgroundBrush() ); wxBrush backgroundBrush( dc.GetBackground() ); dc.SetBrush(* wxWHITE_BRUSH); dc.SetPen(* wxBLACK_PEN); dc.DrawRoundedRectangle(0, 0, CardWidth, CardHeight, 4); if (m_wayUp == facedown) { dc.SetBackground(* wxRED_BRUSH); dc.SetBackgroundMode(wxSOLID); wxBrush* brush = wxTheBrushList->FindOrCreateBrush( "BLACK", wxCROSSDIAG_HATCH ); dc.SetBrush(* brush); dc.DrawRoundedRectangle(4, 4, CardWidth - 8, CardHeight - 8, 2); } else { wxMemoryDC memoryDC; memoryDC.SelectObject(* m_symbolBmap); dc.SetTextBackground(*wxWHITE); switch (m_suit) { case spades: case clubs: dc.SetTextForeground(*wxBLACK); break; case diamonds: case hearts: dc.SetTextForeground(*wxRED); break; } // Draw the value const int suit_width = (int) (CardHeight*11.49/70); wxString ch = ""; ch.Printf("%d", m_pipValue); if (m_pipValue == 11) ch = "J"; if (m_pipValue == 12) ch = "Q"; if (m_pipValue == 13) ch = "K"; if (m_pipValue == 1) ch = "A"; const int w = CardWidth,h = CardHeight; const int sw = suit_width; const int hsw = suit_width/2; const wxSize ss = wxSize(sw,sw); { int num_size = 2*sw/3; int wee_sw = 2*sw/3; DrawNumber(dc, ch, suit_to_color(m_suit) == red, false, 3,3, num_size, num_size); DrawNumber(dc, ch, suit_to_color(m_suit) == red, true, CardWidth-3-num_size,CardHeight-3-num_size, num_size, num_size); // Draw the suit by the number: DrawSuit(dc, m_suit, 1, 2,4+num_size, wee_sw, wee_sw); DrawSuit(dc, m_suit, 0, w-3-wee_sw,h-4-wee_sw-num_size, wee_sw, wee_sw); } // First the middle symbol: switch (m_pipValue) { case 1: case 3: case 9: case 5: DrawSuit(dc, m_suit, 1, w/2-hsw,h/2-hsw, sw, sw); } // Now top and bottom: switch (m_pipValue) { case 2: case 3: DrawSuit(dc, m_suit, 1, w/2-hsw,h/4-hsw, sw, sw); DrawSuit(dc, m_suit, 0, w/2-hsw,3*h/4-hsw, sw, sw); } // Now four outside: switch (m_pipValue) { case 4: case 5: case 6: case 7: case 8: case 9: case 10: DrawSuit(dc, m_suit, 1, w/4-hsw,h/4-hsw, sw, sw); DrawSuit(dc, m_suit, 1, 3*w/4-hsw,h/4-hsw, sw, sw); DrawSuit(dc, m_suit, 0, w/4-hsw,3*h/4-hsw, sw, sw); DrawSuit(dc, m_suit, 0, 3*w/4-hsw,3*h/4-hsw, sw, sw); } // Now two inside: switch (m_pipValue) { case 6: case 7: case 8: DrawSuit(dc, m_suit, 1, w/4-hsw,h/2-hsw, sw, sw); DrawSuit(dc, m_suit, 1, 3*w/4-hsw,h/2-hsw, sw, sw); } // Top third: switch (m_pipValue) { case 7: case 8: DrawSuit(dc, m_suit, 1, w/2-hsw,3*h/8-hsw, sw, sw); } // Bottom third: switch (m_pipValue) { case 8: DrawSuit(dc, m_suit, 0, w/2-hsw,5*h/8-hsw, sw, sw); } // Now four inside: switch (m_pipValue) { case 9: case 10: DrawSuit(dc, m_suit, 1, w/4-hsw,5*h/12-hsw, sw, sw); DrawSuit(dc, m_suit, 1, 3*w/4-hsw,5*h/12-hsw, sw, sw); DrawSuit(dc, m_suit, 0, w/4-hsw,7*h/12-hsw, sw, sw); DrawSuit(dc, m_suit, 0, 3*w/4-hsw,7*h/12-hsw, sw, sw); } // Now two quarters: switch (m_pipValue) { case 10: DrawSuit(dc, m_suit, 1, w/2-hsw,h/3-hsw, sw, sw); DrawSuit(dc, m_suit, 0, w/2-hsw,2*h/3-hsw, sw, sw); } switch (m_pipValue) { case 11: case 12: case 13: memoryDC.SelectObject(* m_pictureBmap); dc.Blit(5+(CardWidth-50)/2, -5 + CardHeight / 4, 40, 45, &memoryDC, 40 * (m_pipValue - 11), 0, wxCOPY); memoryDC.SelectObject(* m_symbolBmap); dc.Blit(32+(CardWidth-50)/2, 3 + CardHeight / 4, 11, 11, &memoryDC, 11 * m_suit, 14, wxCOPY); dc.Blit(7+(CardWidth-50)/2, 27 + CardHeight / 4, 11, 11, &memoryDC, 11 * m_suit, 25, wxCOPY); break; } } cachedbits->SetMask(new wxMask(*cachedbits, aBridgeBackgroundColour())); } outdc.DrawBitmap(*cachedbits, x, y, true); } // Card:Draw() //+-------------------------------------------------------------+ //| Card::GetSuitSymbol() | //+-------------------------------------------------------------+ //| Description: | //| Gets the symbol for a suit and shoves it in a bitmap. | //+-------------------------------------------------------------+ wxBitmap Card::GetSuitSymbol(Suit suit, wxColor back) { wxMemoryDC memoryDC, output; memoryDC.SelectObject(* m_symbolBmap); wxBitmap outbits(11,11); output.SelectObject(outbits); bool use_mask = (back == wxNullColour); if (use_mask) { output.SetTextBackground(aBridgeBackgroundColour()); output.SetBrush(aBridgeBackgroundBrush()); } else { output.SetTextBackground(back); output.SetBrush(wxBrush(back, wxSOLID)); } output.DrawRectangle(-1,-1,12,12); switch (suit) { case spades: case clubs: output.SetTextForeground(*wxBLACK); break; case diamonds: case hearts: output.SetTextForeground(*wxRED); break; } output.Blit(0,0, 11, 11, &memoryDC, 11 * suit, 14, wxCOPY); if (use_mask) { wxMask *mymask = new wxMask(outbits, aBridgeBackgroundColour()); outbits.SetMask(mymask); } return outbits; } int Card::GetCardValue() const { int val = (m_pipValue+11)%13; if (m_suit == clubs) { return val; } else if (m_suit == diamonds) { return val+13; } else if (m_suit == spades) { return val+26; } else if (m_suit == hearts) { return val+39; } else if (m_suit == notrump) { //printf("You can't have a notrump card!\n"); return val; } return 0; // Error here! } bool Card::operator==(const Card &other) const { return GetCardValue() == other.GetCardValue(); } bool Card::operator<(const Card &other) const { return GetCardValue() < other.GetCardValue(); } bool Card::operator>(const Card &other) const { return GetCardValue() > other.GetCardValue(); }