/* * snes9express * profiler.cc * Copyright © 1998-2004 David Nordlund * * 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. * * For further details, please read the included COPYING file, * or go to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include "profiler.h" static const char *TmpState = "new", *SaveState="save", *DefState="default", *DelState="delete"; static const char*NewListData[] = { "error:", "[ Anonymous Profile ]", PROG " error!", (char*)0 }; /// Create the Profiler GUI s9x_Profiler::s9x_Profiler(s9x_Interface*parent): fr_Window(parent, PROG " Profiler"), Logo(0), LogoBox(0), ProfName(this, (char*)0, "", false, S9X_PROFILE_NAME_LEN), BtnOK(this, "Ok"), BtnCancel(this, FR_STOCK_CANCEL), BtnApply(this, FR_STOCK_APPLY), BtnSave(this, FR_STOCK_SAVE), BtnDef(this, FR_STOCK_OPEN, "Default"), BtnDel(this, FR_STOCK_DELETE), def_img(FR_STOCK_OPEN), sav_img(FR_STOCK_SAVE), del_img(FR_STOCK_DELETE), tmp_img(FR_STOCK_NEW), BtnBox(this), ProfileList(this, 3, false), ProfileFile("profiles") { fr_Separator *Separator; InLoading = false; SetGridSize(9, 9, false); NewProfileName = "[ Current ]"; CreateProfileList(); Pack(ProfileList, 2, 0, 9, 5); CreateButtonBar(); Pack(BtnBox, 0, 1, 2, 4); SetStretch(Fill, Fill); ProfName.AddListener(this); ProfName.SetTooltip("To rename the selected profile, type a new name here"); ProfName.AddLabel("Profile Name:"); Pack(ProfName, 2, 5, 9, 6); Separator = new fr_Separator(this, fr_Horizontal); Pack(*Separator, 1, 6, 9, 7); BtnOK.SetTooltip("Save profile changes, Apply the selected profile, and close the Profiler"); BtnCancel.SetTooltip("Close the Profiler, but do not save profile changes"); BtnOK.AddListener(this); BtnCancel.AddListener(this); fr_ButtonBox ButtonBox(this); ButtonBox.AddButton(BtnOK, true); ButtonBox.AddButton(BtnCancel); Pack(ButtonBox, 4, 7, 9, 9); } s9x_Profiler::~s9x_Profiler() { } /// Create the list of profiles void s9x_Profiler::CreateProfileList() { static const char*titles[] = { "", "Profile", "Profile Options", (const char*)0 }; ProfileList.SetHeaders(titles); ProfileList.SetRowHeight(22); ProfileList.SetColumnAlign(0, fr_DataTable::Center); ProfileList.SetColumnWidth(0, 64); ProfileList.SetColumnWidth(1, 180); ProfileList.SetColumnWidth(2); ProfileList.AllowReorder(true); ProfileList.SetSize(400, 300); ProfileList.SetVisibility(true); ProfileList.AddListener(this); } /// Create the button box void s9x_Profiler::CreateButtonBar() { BtnApply.SetTooltip("Apply the selected profile(s) to the snes9express" " interface. If multiple profiles are selected," " they will be merged."); BtnApply.AddListener(this); BtnSave.SetTooltip("Mark the selected profile(s) to be saved"); BtnSave.AddListener(this); BtnDef.SetTooltip("Mark the selected profile to be the Default " "profile. The Default profile will be loaded " "automatically when " PROG " is started"); BtnDef.AddListener(this); BtnDel.SetTooltip("Mark the selected profile(s) not to be saved"); BtnDel.SetEditable(false); BtnDel.AddListener(this); BtnBox.SetGridSize(1, 4, true); BtnBox.Pack(BtnApply); BtnBox.Pack(BtnSave); BtnBox.Pack(BtnDef); BtnBox.Pack(BtnDel); BtnBox.AddBorderBevelIn(); BtnBox.SetVisibility(true); } /// Set the profile data for a given row void s9x_Profiler::SetProfile(int r, s9x_ProfileState s, const std::string& N, const std::string& A) { SetRowState(r, s); ProfileList.SetCell(r, 1, N); ProfileList.SetCell(r, 2, A); } /// Set the state of a given row void s9x_Profiler::SetRowState(int row, s9x_ProfileState s) { if((row<0)||(row>=ProfileList.CountRows())) return; switch(s) { case S9X_PROFILE_STATE_DEFAULT: ProfileList.SetCell(row, 0, DefState, &def_img); break; case S9X_PROFILE_STATE_SAVED: ProfileList.SetCell(row, 0, SaveState, &sav_img); break; case S9X_PROFILE_STATE_DELETED: ProfileList.SetCell(row, 0, DelState, &del_img); break; case S9X_PROFILE_STATE_TEMP: ProfileList.SetCell(row, 0, TmpState, &tmp_img); break; }; } /// Get the state of a given row s9x_ProfileState s9x_Profiler::GetRowState(int row) { if((row<0)||(row>=ProfileList.CountRows())) return S9X_PROFILE_STATE_TEMP; const fr_Image *i = ProfileList.GetCellPic(row, 0); if(i==&def_img) return S9X_PROFILE_STATE_DEFAULT; if(i==&sav_img) return S9X_PROFILE_STATE_SAVED; if(i==&del_img) return S9X_PROFILE_STATE_DELETED; return S9X_PROFILE_STATE_TEMP; } /// Get the name of a given row std::string s9x_Profiler::GetRowName(int row) { if((row<0)||(row>=ProfileList.CountRows())) return ""; return ProfileList.GetCell(row, 1); } /// Get the args of a given row std::string s9x_Profiler::GetRowArgsEncoded(int row) { if((row<0)||(row>=ProfileList.CountRows())) return ""; return ProfileList.GetCell(row, 2); } /// Get the ArgList for a given row fr_ArgList*s9x_Profiler::GetRowArgList(int row) { if((row<0)||(row>=ProfileList.CountRows())) return (fr_ArgList*)0; std::string a = ProfileList.GetCell(row, 2); if(a.size()==0) return (fr_ArgList*)0; return new fr_ArgList(a.c_str()); } /// Find the row with the default profile int s9x_Profiler::GetDefaultRow() { int i, CountProfiles = ProfileList.CountRows(); for(i=0; i0) { try { ProfileFile.open(outfile); outfile << "snes9express profiles" << std::endl; DefaultRow = GetDefaultRow(); if(DefaultRow>-1) { std::string dn = GetRowName(DefaultRow); if(dn.size()) outfile << "DEFAULT " << dn << std::endl << std::endl; } for(i=0; i> buf; // PROG if(buf!=PROG) oldformat = true; infile >> buf; // profiles while(infile >> buf) { fl++; if(!buf.size()) continue; if(buf[0]=='#') { std::getline(infile, buf); continue; } if(buf=="PROFILE") { infile.ignore(1, ' '); std::getline(infile, nameholder); } else if(buf=="DEFAULT") { if(defaultname.size()) std::cerr << "Duplicate default \"" << buf << "\", " << "line "<< fl << std::endl; infile.ignore(1, ' '); std::getline(infile, defaultname); } else if(buf=="OPTIONS") { options.clear(9); if(oldformat) { infile.ignore(1, ' '); infile.getline(oldbuf, 1023); oldbuf[1023] = 0; options.loadUrlEncodedArgs(oldbuf); } else infile >> options; if(!options.CountArgs()) continue; newrownum = ProfileList.CountRows(); if(nameholder==defaultname) DefaultRow = newrownum; ProfileList.AddRow(NewListData); SetProfile(newrownum, S9X_PROFILE_STATE_SAVED, nameholder, options.GetString()); nameholder = NewListData[1]; } } ProfileFile.close(infile); if(DefaultRow>-1) SetRowState(DefaultRow, S9X_PROFILE_STATE_DEFAULT); if(oldformat) SaveList(); } catch (...) { Mesg("error opening profiles"); ProfileFile.close(infile); } time(&LastModified); ProfileList.Freeze(false); ProfileList.SetEditable(true); InLoading = false; return 0; } /// Show or hide the entire Profiler window void s9x_Profiler::SetVisibility(bool s) { int i = -1, match = -1, CountProfiles = ProfileList.CountRows(); struct stat statbuf; /* unselect all rows */ ProfileList.DeselectAll(); if(s) { //reload profiles if file is more recent than whats in mem if((ProfileFile.stat(&statbuf)==0) &&(statbuf.st_mtime > LastModified)) LoadList(); CountProfiles = ProfileList.CountRows(); //match current interface to a profile, or add new entry fr_ArgList ArgList(20); ((s9x_Interface*)Parent)->CompileArgs(ArgList); std::string CurrentArgs = ArgList.GetString(); if(CurrentArgs.size()) { for(i=0; i-1) &&((ArgList = GetRowArgList(row))!=NULL)) { ((s9x_Interface*)Parent)->SiftArgs(*ArgList); delete ArgList; } } /// Apply the selected rows to the main interface void s9x_Profiler::Apply() { int i, p, CountSelected; ((s9x_Interface*)Parent)->SetToDefaults(); CountSelected = ProfileList.CountSelectedRows(); for(i=0; i=0) ApplyRow(p); } if(CountSelected > 1) { const char*SavedName = NewProfileName; NewProfileName = "[ Merged ]"; SetVisibility(true); NewProfileName = SavedName; } } /// Apply the default profile to the main interface void s9x_Profiler::ApplyDefaultProfile() { if(ProfileList.CountRows() < 1) LoadList(); ApplyRow(GetDefaultRow()); } /// A row in the list has been clicked void s9x_Profiler::RowSelected(int row) { int SelectedRow, CountRows; SelectedRow = ProfileList.GetSelected(0); InLoading = true; if(SelectedRow>=0) { ProfName.SetEditable(true); ProfName.SetText(GetRowName(SelectedRow)); BtnApply.SetEditable(true); } else { ProfName.SetText(""); ProfName.SetEditable(false); CountRows = ProfileList.CountSelectedRows(); BtnApply.SetEditable(CountRows>1); BtnSave.SetEditable(CountRows>1); BtnDef.SetEditable(false); BtnDel.SetEditable(CountRows>1); InLoading = false; return; }; InLoading = false; switch(GetRowState(SelectedRow)) { case S9X_PROFILE_STATE_DELETED: BtnDel.SetEditable(false); BtnSave.SetEditable(true); BtnDef.SetEditable(false); ProfName.SetEditable(false); break; case S9X_PROFILE_STATE_TEMP: BtnDel.SetEditable(false); BtnSave.SetEditable(true); BtnDef.SetEditable(false); break; case S9X_PROFILE_STATE_SAVED: BtnDel.SetEditable(true); BtnSave.SetEditable(false); BtnDef.SetEditable(true); break; case S9X_PROFILE_STATE_DEFAULT: BtnDel.SetEditable(true); BtnSave.SetEditable(true); BtnDef.SetEditable(false); break; }; } /// Change the state of the selected profile(s) void s9x_Profiler::ChangeState(s9x_ProfileState s) { int i, CountSelected, p=-1; CountSelected = ProfileList.CountSelectedRows(); if(CountSelected<1) return; if(s==S9X_PROFILE_STATE_DEFAULT) { if(CountSelected!=1) return; i = GetDefaultRow(); if(i>=0) SetRowState(i, S9X_PROFILE_STATE_SAVED); SetRowState(GetSelectedRow(), s); } else for(i=0; i=0) SetRowState(p, s); }; if(p>=0) RowSelected(p); } /// The name of the selected profile has been updated void s9x_Profiler::NameUpdated() { int SelectedRow; if(InLoading) return; SelectedRow = GetSelectedRow(); if(SelectedRow>=0) { ProfileList.SetCell(SelectedRow, 1, ProfName.GetText()); if(GetRowState(SelectedRow)!=S9X_PROFILE_STATE_DEFAULT) ChangeState(S9X_PROFILE_STATE_SAVED); }; } void s9x_Profiler::ApplySkin(s9x_Skin*S) { s9x_SkinSection* section = S?S->getSection("icons"):NULL; fr_Image* logo = section?section->getImage("logo"):NULL; setIcon(logo); if(Logo) { LogoBox->Remove(*Logo); Remove(*LogoBox); delete Logo; delete LogoBox; Logo = 0; LogoBox = 0; } if(logo) { Logo = new fr_Element(this, *logo); LogoBox = new fr_Box(this); LogoBox->SetGridSize(1, 1, false); LogoBox->SetPadding(0, 0); SetStretch(Shrink, Shrink); LogoBox->Pack(*Logo); LogoBox->AddBorderBevelIn(); LogoBox->SetVisibility(true); Pack(*LogoBox, 0, 6, 1, 9); } } /// Handle events generated within the Profiler void s9x_Profiler::EventOccurred(fr_Event*e) { int SelectedRow; SelectedRow = GetSelectedRow(); if(e->Is(BtnDel)) ChangeState(S9X_PROFILE_STATE_DELETED); else if(e->Is(BtnDef)) ChangeState(S9X_PROFILE_STATE_DEFAULT); else if(e->Is(BtnSave)) ChangeState(S9X_PROFILE_STATE_SAVED); else if(e->Is(ProfileList, fr_Click)) ProfileList.Sort(); else if(e->Is(ProfileList, fr_Select)) RowSelected(e->intArg); else if(e->Is(ProfName, fr_Changed)) NameUpdated(); //else if(e->Is(ProfName)) // BtnOK.GrabFocus(); // not sure why, but this goes insane. else if(e->Is(BtnApply)||e->Is(BtnOK)||e->Is(ProfileList, fr_DoubleClick)) Apply(); else if(e->Is(BtnCancel)||e->Is(this, fr_Destroy)) { LastModified = 0; ProfileList.RemoveAll(); SetVisibility(false); }; if(e->Is(BtnApply)) { fr_Flush(); SetVisibility(true); } if(e->Is(BtnOK)||e->Is(ProfileList, fr_DoubleClick)) { if(SaveList()==0) SetVisibility(false); }; }