copy_paste_gui.cpp

00001 /* $Id: copy_paste_gui.cpp 4998 2006-05-28 07:45:14Z Frostregen $ */
00002 
00003 #include "stdafx.h"
00004 #include "openttd.h"
00005 #include "gui.h"
00006 #include "window_gui.h"
00007 #include "viewport_type.h"
00008 #include "viewport_func.h"
00009 #include "gfx_func.h"
00010 #include "strings_type.h"
00011 #include "clear_func.h"
00012 #include "window_type.h"
00013 #include "window_func.h"
00014 #include "sound_type.h"
00015 #include "sound_func.h"
00016 #include "tilehighlight_type.h"
00017 #include "tilehighlight_func.h"
00018 #include "company_func.h"
00019 #include "tile_type.h"
00020 #include "rail_type.h"
00021 #include "rail_gui.h"
00022 #include "sprite.h"
00023 #include "fios.h"
00024 #include "copy_paste.h"
00025 #include "table/sprites.h"
00026 #include "table/strings.h"
00027 
00028 
00030 static RailType _last_railtype = RAILTYPE_RAIL;
00031 
00032 /* **** GUI Code for Copy&Paste **** */
00033 
00035 enum CopyPasteWidgets {
00036   CPW_CLOSEBOX = 0,
00037   CPW_CAPTION,
00038   CPW_STICKYBOX,
00039   CPW_SPACER_1,
00040   CPW_SPACER_2,
00041   CPW_SPACER_3,
00042   CPW_COPY,
00043   CPW_PASTE,
00044   CPW_LOAD,
00045   CPW_SAVE,
00046   CPW_ROTATE_LEFT,
00047   CPW_ROTATE_RIGHT,
00048   CPW_MIRROR_HORIZONTAL,
00049   CPW_MIRROR_VERTICAL,
00050   CPW_TERRAIN,
00051   CPW_DYNAMITE,
00052   CPW_RAIL,
00053   CPW_ROAD,
00054   CPW_REVERSE_SIGNALS,
00055   CPW_CONVERT_RAILTYPE,
00056   CPW_ONLY_OWN,
00057 
00058   CPW_FIRST_CLICKABLE = CPW_COPY,
00059   CPW_LAST_CLICKABLE = CPW_ONLY_OWN,
00060 };
00061 
00062 struct CopyPasteWindow : Window {
00063 int last_user_action; 
00064 public:
00065   CopyPasteWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00066   {
00067     this->InitNested(desc, window_number);
00068     this->last_user_action = WIDGET_LIST_END;
00069 
00070     /* Set the button states according to variable content */
00071     if (_copy_paste.m_clear_before_build) this->LowerWidget(CPW_DYNAMITE);
00072     if (_copy_paste.m_toggle_signal_direction) this->LowerWidget(CPW_REVERSE_SIGNALS);
00073     if (_copy_paste.m_convert_rail)   this->LowerWidget(CPW_CONVERT_RAILTYPE);
00074     if (_copy_paste.m_copy_with_rail) this->LowerWidget(CPW_RAIL);
00075     if (_copy_paste.m_copy_with_road) this->LowerWidget(CPW_ROAD);
00076     if (_copy_paste.m_copy_with_other)this->LowerWidget(CPW_ONLY_OWN);
00077   }
00078 
00079   virtual void OnPaint()
00080   {
00081     SetWidgetsDisabledState(!_copy_paste.IsSomethingCopied(), CPW_PASTE, CPW_SAVE,
00082         CPW_ROTATE_LEFT, CPW_ROTATE_RIGHT, CPW_MIRROR_HORIZONTAL, CPW_MIRROR_VERTICAL,
00083         WIDGET_LIST_END);
00084     /* Set image for tri-state button */
00085     this->GetWidget<NWidgetCore>(CPW_TERRAIN)->widget_data = SPR_IMG_MINUS_TERRAIN + _copy_paste.m_paste_vacant_terrain;
00086 
00087     this->DrawWidgets();
00088 
00089     /* Draw CylinderGuy in CompanyColor, if unclicked */
00090     if (!this->IsWidgetLowered(CPW_ONLY_OWN))
00091       DrawSprite(SPR_IMG_ONLY_OWN, COMPANY_SPRITE_COLOUR(_current_company), this->GetWidget<NWidgetCore>(CPW_ONLY_OWN)->pos_x + 1, this->GetWidget<NWidgetCore>(CPW_ONLY_OWN)->pos_y + 1);
00092   }
00093 
00094   virtual void OnClick(Point pt, int widget, int click_count)
00095   {
00096     SetWidgetsDisabledState(!_copy_paste.IsSomethingCopied(), CPW_PASTE, CPW_SAVE,
00097         CPW_ROTATE_LEFT, CPW_ROTATE_RIGHT, CPW_MIRROR_HORIZONTAL, CPW_MIRROR_VERTICAL,
00098         WIDGET_LIST_END);
00099     if (this->IsWidgetDisabled(widget)) return;
00100     if ((widget >= CPW_FIRST_CLICKABLE) && (widget <= CPW_LAST_CLICKABLE)) {
00101       if (widget != CPW_COPY && widget != CPW_PASTE && 
00102         widget != CPW_DYNAMITE && widget != CPW_REVERSE_SIGNALS && 
00103         widget != CPW_RAIL && widget !=  CPW_CONVERT_RAILTYPE && 
00104         widget != CPW_ROAD && widget != CPW_ONLY_OWN) {
00105         this->HandleButtonClick(widget);
00106       }
00107       SndPlayFx(SND_15_BEEP);
00108       switch (widget) {
00109         case CPW_COPY:
00110           HandlePlacePushButton(this, CPW_COPY, SPR_CURSOR_COPY, HT_RECT);
00111           this->last_user_action = widget;
00112           break;
00113 
00114         case CPW_PASTE:
00115           HandlePlacePushButton(this, CPW_PASTE, SPR_CURSOR_PASTE, HT_PREVIEW);
00116           this->last_user_action = widget;
00117           break;
00118 
00119         case CPW_LOAD:
00120           _copy_paste.m_toggle_signal_direction = false;
00121           /* fallthrough */
00122 
00123         case CPW_SAVE:
00124           ShowSaveLoadDialog(widget == CPW_SAVE ? SLD_SAVE_TEMPLATE : SLD_LOAD_TEMPLATE);
00125           break;
00126 
00127         case CPW_ROTATE_LEFT:
00128         case CPW_ROTATE_RIGHT:
00129           if (widget == CPW_ROTATE_LEFT)  _copy_paste.RotateSelectionCCW();
00130           if (widget == CPW_ROTATE_RIGHT) _copy_paste.RotateSelectionCW();
00131           break;
00132 
00133         case CPW_MIRROR_HORIZONTAL:
00134         case CPW_MIRROR_VERTICAL:
00135           if (widget == CPW_MIRROR_HORIZONTAL) _copy_paste.MirrorSelectionHorizontal();
00136           if (widget == CPW_MIRROR_VERTICAL)   _copy_paste.MirrorSelectionVertical();
00137           
00138           /* Toggle SignalDir */
00139           this->OnClick(Point(), CPW_REVERSE_SIGNALS, 1);
00140           break;
00141 
00142         case CPW_TERRAIN:
00143           _copy_paste.m_paste_vacant_terrain++;
00144           if (_copy_paste.m_paste_vacant_terrain > 2) _copy_paste.m_paste_vacant_terrain = 0;
00145           break;
00146 
00147         case CPW_DYNAMITE: case CPW_REVERSE_SIGNALS:
00148         case CPW_RAIL: case CPW_CONVERT_RAILTYPE:
00149         case CPW_ROAD: case CPW_ONLY_OWN: {
00150           this->SetDirty();
00151           this->ToggleWidgetLoweredState(widget);
00152           bool state = IsWidgetLowered(widget);
00153           switch (widget) {
00154             case CPW_DYNAMITE:         _copy_paste.m_clear_before_build = state; break;
00155             case CPW_RAIL:             _copy_paste.m_copy_with_rail = state; break;
00156             case CPW_ROAD:             _copy_paste.m_copy_with_road = state; break;
00157             case CPW_REVERSE_SIGNALS:  _copy_paste.m_toggle_signal_direction = state; break;
00158             case CPW_CONVERT_RAILTYPE: _copy_paste.m_convert_rail = state; break;
00159             case CPW_ONLY_OWN:         _copy_paste.m_copy_with_other = state; break;
00160             default: NOT_REACHED();
00161           }
00162         } break;
00163         default: break;
00164       }
00165 
00166       /* Set Selection size to Copy size */
00167       if (this->IsWidgetLowered(CPW_PASTE)) {
00168         if (_copy_paste.GetWidth() > 0)
00169           SetTileSelectSize(_copy_paste.GetWidth() - 1, _copy_paste.GetHeight() - 1);
00170       } else {
00171         SetTileSelectSize(1, 1);
00172       }
00173     }
00174   }
00175 
00176   virtual void OnPlaceObject(Point pt, TileIndex tile)
00177   {
00178     switch (this->last_user_action) { 
00179       case CPW_COPY:
00180         VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_COPY_AREA);
00181         VpSetPlaceSizingLimit(255);
00182         break;
00183 
00184       case CPW_PASTE:
00185         _copy_paste.PasteArea(tile);
00186         break;
00187     }
00188   }
00189 
00190   virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
00191   {
00192     VpSelectTilesWithMethod(pt.x, pt.y, select_method);
00193   }
00194 
00195   virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
00196   {
00197     if (pt.x != -1) {
00198       switch (select_proc) {
00199         case DDSP_COPY_AREA:
00200           _copy_paste.CopyArea(end_tile, start_tile);
00201           /* Reset SignalDir */
00202           if (_copy_paste.m_toggle_signal_direction) this->OnClick(Point(), CPW_REVERSE_SIGNALS, 1);
00203           this->SetDirty();
00204           break;
00205         default:
00206           break;
00207       }
00208     }
00209   }
00210 
00211   virtual void OnPlaceObjectAbort()
00212   {
00213     /* UnclickWindowButtons "copy" and "paste" */
00214     this->RaiseWidget(CPW_COPY);
00215     this->RaiseWidget(CPW_PASTE);
00216 
00217     this->SetDirty();
00218   }
00219 
00220   virtual void OnTimeout()
00221   {
00222     this->RaiseWidget(CPW_LOAD);
00223     this->RaiseWidget(CPW_SAVE);
00224     this->RaiseWidget(CPW_ROTATE_LEFT);
00225     this->RaiseWidget(CPW_ROTATE_RIGHT);
00226     this->RaiseWidget(CPW_MIRROR_HORIZONTAL);
00227     this->RaiseWidget(CPW_MIRROR_VERTICAL);
00228     this->RaiseWidget(CPW_TERRAIN);
00229     this->SetDirty();
00230   }
00231 
00232   virtual void OnTick()
00233   {
00234     /* If railtype has changed, we need to update our GUI */
00235     if (_last_railtype != _cur_railtype) {
00236       const RailtypeInfo *rti = GetRailTypeInfo(_cur_railtype);
00237       _last_railtype = _cur_railtype;
00238       this->GetWidget<NWidgetCore>(CPW_CONVERT_RAILTYPE)->widget_data = rti->gui_sprites.convert_rail;
00239       this->SetDirty();
00240     }
00241   }
00242 };
00243 
00244 static const NWidgetPart _nested_copy_paste_widgets[] = {
00245   NWidget(NWID_HORIZONTAL),
00246     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
00247     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_COPY_PASTE_TOOLBAR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00248     NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
00249   EndContainer(),
00250   NWidget(NWID_HORIZONTAL),
00251     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_COPY), SetMinimalSize(22,22),
00252                 SetFill(0, 1), SetDataTip(SPR_IMG_COPY,              STR_COPY_PASTE_COPY_TOOLTIP),
00253     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_PASTE), SetMinimalSize(22,22),
00254                 SetFill(0, 1), SetDataTip(SPR_IMG_PASTE,             STR_COPY_PASTE_PASTE_TOOLTIP),
00255 
00256     NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(),
00257 
00258     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_LOAD), SetMinimalSize(22,22),
00259                 SetFill(0, 1), SetDataTip(SPR_IMG_LOAD,              STR_COPY_PASTE_LOAD_TOOLTIP),
00260     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_SAVE), SetMinimalSize(22,22),
00261                 SetFill(0, 1), SetDataTip(SPR_IMG_SAVE,              STR_COPY_PASTE_SAVE_TOOLTIP),
00262 
00263     NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(),
00264 
00265     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_ROTATE_LEFT), SetMinimalSize(22,22),
00266                 SetFill(0, 1), SetDataTip(SPR_IMG_ROTATE_LEFT,       STR_COPY_PASTE_ROTATE_LEFT_TOOLTIP),
00267     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_ROTATE_RIGHT), SetMinimalSize(22,22),
00268                 SetFill(0, 1), SetDataTip(SPR_IMG_ROTATE_RIGHT,      STR_COPY_PASTE_ROTATE_RIGHT_TOOLTIP),
00269     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_MIRROR_HORIZONTAL), SetMinimalSize(22,22),
00270                 SetFill(0, 1), SetDataTip(SPR_IMG_MIRROR_HORIZONTAL, STR_COPY_PASTE_MIRROR_HORIZONTAL_TOOLTIP),
00271     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_MIRROR_VERTICAL), SetMinimalSize(22,22),
00272                 SetFill(0, 1), SetDataTip(SPR_IMG_MIRROR_VERTICAL,   STR_COPY_PASTE_MIRROR_VERTICAL_TOOLTIP),
00273 
00274     NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(),
00275 
00276     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_TERRAIN), SetMinimalSize(22,22),
00277                 SetFill(0, 1), SetDataTip(SPR_IMG_MINUS_TERRAIN,     STR_COPY_PASTE_VACANT_TERRAIN_TOOLTIP),
00278     NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_DYNAMITE), SetMinimalSize(22,22),
00279                 SetFill(0, 1), SetDataTip(SPR_IMG_MINUS_DYNAMITE,    STR_COPY_PASTE_BULLDOZE_BEFORE_BUILD_TOOLTIP),
00280     NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_RAIL), SetMinimalSize(22,22),
00281                 SetFill(0, 1), SetDataTip(SPR_IMG_NO_RAIL,           STR_COPY_PASTE_WITHOUT_RAIL_TOOLTIP),
00282     NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_ROAD), SetMinimalSize(22,22),
00283                 SetFill(0, 1), SetDataTip(SPR_IMG_NO_ROAD,           STR_COPY_PASTE_WITHOUT_ROAD_TOOLTIP),
00284     NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_REVERSE_SIGNALS), SetMinimalSize(22,22),
00285                 SetFill(0, 1), SetDataTip(SPR_IMG_MINUS_SIGNAL,      STR_COPY_PASTE_TOGGLE_SIGNAL_DIRECTION_TOOLTIP),
00286     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CPW_CONVERT_RAILTYPE), SetMinimalSize(22,22),
00287                 SetFill(0, 1), SetDataTip(SPR_IMG_CONVERT_RAIL,      STR_COPY_PASTE_CONVERT_RAIL_TOOLTIP),
00288     NWidget(WWT_IMGBTN_2, COLOUR_DARK_GREEN, CPW_ONLY_OWN), SetMinimalSize(22,22),
00289                 SetFill(0, 1), SetDataTip(SPR_IMG_ONLY_OWN,          STR_COPY_PASTE_ONLY_OWN_TOOLTIP),
00290   EndContainer(),
00291 };
00292 
00293 static const WindowDesc _copy_paste_desc(
00294   WDP_ALIGN_TOOLBAR, 0, 0,
00295   WC_COPY_PASTE, WC_SCEN_LAND_GEN,
00296   WDF_CONSTRUCTION,
00297   _nested_copy_paste_widgets, lengthof(_nested_copy_paste_widgets)
00298 );
00299 
00300 void ShowCopyPasteToolbarGui() // When clicking the button in the terrain generation gui
00301 {
00302   AllocateWindowDescFront<CopyPasteWindow>(&_copy_paste_desc, 0);
00303 }
00304 
00305 void ShowCopyPasteToolbar(int button) // When using a shortcut
00306 {
00307   Window *w;
00308   /* don't recreate the window if we're clicking on a button and the window exists. */
00309   if (button < CPW_FIRST_CLICKABLE || !(w = FindWindowById(WC_COPY_PASTE, 0))) {
00310     DeleteWindowByClass(WC_COPY_PASTE);
00311     w = new CopyPasteWindow(&_copy_paste_desc, 0);
00312   }
00313   if (w != NULL) w->OnClick(Point(), button, 1);
00314 }