void TableWidget::Sync( const SizerWidget *p_sizer )
{
    assert( !p_sizer->_need_update );
    StupidVector<Belt> cells = p_sizer->GetCells();
    bool horiz = p_sizer->IsHorizontal();
    
    if ( !cells.empty() )
    {
        int begin = (*cells.begin())._position;
        int end = (*cells.rbegin())._position;

        (*cells.rbegin())._size = ((horiz) ? GetWidth() : GetHeight())-end;
        (*cells.begin())._size += begin-((horiz)? _frame_left : _frame_top);
    }
    if (horiz) SetupColumns( cells ); else SetupRows( cells );
}
BOOL Dlg_AchievementsReporter::OnInitDialog(HWND hwnd, _UNUSED HWND hwndFocus,
	_UNUSED LPARAM lParam)
{
	m_hList = GetDlgItem(hwnd, IDC_RA_REPORTBROKENACHIEVEMENTSLIST);
	SetupColumns();

	for (size_t i = 0; i < g_pActiveAchievements->NumAchievements(); ++i)
	{
		AddAchievementToListBox(&g_pActiveAchievements->GetAchievement(i));
	} // end for

	ListView_SetExtendedListViewStyle(m_hList,
		LVS_EX_CHECKBOXES | LVS_EX_HEADERDRAGDROP);

	m_hBugReporter = GetDlgItem(hwnd, IDC_RA_BROKENACH_BUGREPORTER);
	SetText(m_hBugReporter, cusername());
	return FALSE;
} // end function OnInitDialog
INT_PTR CALLBACK Dlg_GameLibrary::GameLibraryProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_INITDIALOG:
	{
		HWND hList = GetDlgItem(hDlg, IDC_RA_LBX_GAMELIST);
		SetupColumns(hList);

		ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);

		SetDlgItemText(hDlg, IDC_RA_ROMDIR, NativeStr(g_sROMDirLocation).c_str());
		SetDlgItemText(hDlg, IDC_RA_GLIB_NAME, TEXT(""));

		m_GameHashLibrary.clear();
		m_GameTitlesLibrary.clear();
		m_ProgressLibrary.clear();
		ParseGameHashLibraryFromFile(m_GameHashLibrary);
		ParseGameTitlesFromFile(m_GameTitlesLibrary);
		ParseMyProgressFromFile(m_ProgressLibrary);

		//int msBetweenRefresh = 1000;	//	auto?
		//SetTimer( hDlg, 1, msBetweenRefresh, (TIMERPROC)g_GameLibrary.s_GameLibraryProc );
		RefreshList();

		return FALSE;
	}

	case WM_TIMER:
		if ((g_GameLibrary.GetHWND() != NULL) && (IsWindowVisible(g_GameLibrary.GetHWND())))
			RefreshList();
		//ReloadGameListData();
		return FALSE;

	case WM_NOTIFY:
		switch (LOWORD(wParam))
		{
		case IDC_RA_LBX_GAMELIST:
		{
			switch (((LPNMHDR)lParam)->code)
			{
			case LVN_ITEMCHANGED:
			{
				//RA_LOG( "Item Changed\n" );
				HWND hList = GetDlgItem(hDlg, IDC_RA_LBX_GAMELIST);
				const int nSel = ListView_GetSelectionMark(hList);
				if (nSel != -1)
				{
					TCHAR buffer[1024];
					ListView_GetItemText(hList, nSel, 1, buffer, 1024);
					SetWindowText(GetDlgItem(hDlg, IDC_RA_GLIB_NAME), buffer);
				}
			}
			break;

			case NM_CLICK:
				//RA_LOG( "Click\n" );
				break;

			case NM_DBLCLK:
				if (LaunchSelected())
				{
					EndDialog(hDlg, TRUE);
					return TRUE;
				}
				break;

			default:
				break;
			}
		}
		return FALSE;

		default:
			RA_LOG("%08x, %08x\n", wParam, lParam);
			return FALSE;
		}

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			if (LaunchSelected())
			{
				EndDialog(hDlg, TRUE);
				return TRUE;
			}
			else
			{
				return FALSE;
			}

		case IDC_RA_RESCAN:
			ReloadGameListData();

			mtx.lock();	//?
			SetDlgItemText(m_hDialogBox, IDC_RA_SCANNERFOUNDINFO, TEXT("Scanning..."));
			mtx.unlock();
			return FALSE;

		case IDC_RA_PICKROMDIR:
			g_sROMDirLocation = GetFolderFromDialog();
			RA_LOG("Selected Folder: %s\n", g_sROMDirLocation.c_str());
			SetDlgItemText(hDlg, IDC_RA_ROMDIR, NativeStr(g_sROMDirLocation).c_str());
			return FALSE;

		case IDC_RA_LBX_GAMELIST:
		{
			HWND hList = GetDlgItem(hDlg, IDC_RA_LBX_GAMELIST);
			const int nSel = ListView_GetSelectionMark(hList);
			if (nSel != -1)
			{
				TCHAR sGameTitle[1024];
				ListView_GetItemText(hList, nSel, 1, sGameTitle, 1024);
				SetWindowText(GetDlgItem(hDlg, IDC_RA_GLIB_NAME), sGameTitle);
			}
		}
		return FALSE;

		case IDC_RA_REFRESH:
			RefreshList();
			return FALSE;

		default:
			return FALSE;
		}

	case WM_PAINT:
		if (nNumParsed != Results.size())
			nNumParsed = Results.size();
		return FALSE;

	case WM_CLOSE:
		EndDialog(hDlg, FALSE);
		return TRUE;

	case WM_USER:
		return FALSE;

	default:
		return FALSE;
	}
}
INT_PTR CALLBACK Dlg_AchievementsReporter::AchievementsReporterProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	switch( uMsg )
	{
		case WM_INITDIALOG:
		{
			HWND hList = GetDlgItem( hDlg, IDC_RA_REPORTBROKENACHIEVEMENTSLIST );
			SetupColumns( hList );

			for( size_t i = 0; i < g_pActiveAchievements->NumAchievements(); ++i )
				AddAchievementToListBox( hList, &g_pActiveAchievements->GetAchievement( i ) );

			ListView_SetExtendedListViewStyle( hList, LVS_EX_CHECKBOXES | LVS_EX_HEADERDRAGDROP );
			SetDlgItemText( hDlg, IDC_RA_BROKENACH_BUGREPORTER, Widen( RAUsers::LocalUser().Username() ).c_str() );
		}
		return FALSE;

	case WM_COMMAND:
		switch( LOWORD( wParam ) )
		{
		case IDOK:
		{
			HWND hList = GetDlgItem( hDlg, IDC_RA_REPORTBROKENACHIEVEMENTSLIST );

			const bool bProblem1Sel = ( IsDlgButtonChecked( hDlg, IDC_RA_PROBLEMTYPE1 ) == BST_CHECKED );
			const bool bProblem2Sel = ( IsDlgButtonChecked( hDlg, IDC_RA_PROBLEMTYPE2 ) == BST_CHECKED );

			if( ( bProblem1Sel == false ) && ( bProblem2Sel == false ) )
			{
				MessageBox( nullptr, L"Please select a problem type.", L"Warning", MB_ICONWARNING );
				return FALSE;
			}

			int nProblemType = bProblem1Sel ? 1 : bProblem2Sel ? 2 : 0;	// 0==?
			const char* sProblemTypeNice = PROBLEM_STR[ nProblemType ];

			char sBuggedIDs[ 1024 ];
			sprintf_s( sBuggedIDs, 1024, "" );

			int nReportCount = 0;

			const size_t nListSize = ListView_GetItemCount( hList );
			for( size_t i = 0; i < nListSize; ++i )
			{
				if( ListView_GetCheckState( hList, i ) != 0 )
				{
					//	NASTY big assumption here...
					char buffer[ 1024 ];
					sprintf_s( buffer, 1024, "%d,", g_pActiveAchievements->GetAchievement( i ).ID() );
					strcat_s( sBuggedIDs, 1024, buffer );

					//ListView_GetItem( hList );	
					nReportCount++;
				}
			}

			if( nReportCount > 5 )
			{
				if( MessageBox( nullptr, L"You have over 5 achievements selected. Is this OK?", L"Warning", MB_YESNO ) == IDNO )
					return FALSE;
			}

			wchar_t sBugReportCommentWide[ 4096 ];
			GetDlgItemText( hDlg, IDC_RA_BROKENACHIEVEMENTREPORTCOMMENT, sBugReportCommentWide, 4096 );
			std::string sBugReportComment = Narrow( sBugReportCommentWide );

			char sBugReportInFull[ 8192 ];
			sprintf_s( sBugReportInFull, 8192,
					"--New Bug Report--\n"
					"\n"
					"Game: %s\n"
					"Achievement IDs: %s\n"
					"Problem: %s\n"
					"Reporter: %s\n"
					"ROM Checksum: %s\n"
					"\n"
					"Comment: %s\n"
					"\n"
					"Is this OK?",
					CoreAchievements->GameTitle().c_str(),
					sBuggedIDs,
					sProblemTypeNice,
					RAUsers::LocalUser().Username().c_str(),
					g_sCurrentROMMD5.c_str(),
					sBugReportComment.c_str() );

			if( MessageBox( nullptr, Widen( sBugReportInFull ).c_str(), L"Summary", MB_YESNO ) == IDNO )
				return FALSE;

			PostArgs args;
			args[ 'u' ] = RAUsers::LocalUser().Username();
			args[ 't' ] = RAUsers::LocalUser().Token();
			args[ 'i' ] = sBuggedIDs;
			args[ 'p' ] = std::to_string( nProblemType );
			args[ 'n' ] = sBugReportComment.c_str();
			args[ 'm' ] = g_sCurrentROMMD5;

			Document doc;
			if( RAWeb::DoBlockingRequest( RequestSubmitTicket, args, doc ) )
			{
				if( doc[ "Success" ].GetBool() )
				{
					char buffer[ 2048 ];
					sprintf_s( buffer, 2048, "Submitted OK!\n"
							"\n"
							"Thankyou for reporting that bug(s), and sorry it hasn't worked correctly.\n"
							"\n"
							"The development team will investigate this bug as soon as possible\n"
							"and we will send you a message on RetroAchievements.org\n"
							"as soon as we have a solution.\n"
							"\n"
							"Thanks again!" );

					MessageBox( hDlg, Widen( buffer ).c_str(), L"Success!", MB_OK );
					EndDialog( hDlg, TRUE );
					return TRUE;
				}
				else
				{
					char buffer[ 2048 ];
					sprintf_s( buffer, 2048,
							"Failed!\n"
							"\n"
							"Response From Server:\n"
							"\n"
							"Error code: %d", doc.GetParseError() );
					MessageBox( hDlg, Widen( buffer ).c_str(), L"Error from server!", MB_OK );
					return FALSE;
				}
			}
			else
			{
				MessageBox( hDlg,
							L"Failed!\n"
							L"\n"
							L"Cannot reach server... are you online?\n"
							L"\n",
							L"Error!", MB_OK );
				return FALSE;
			}
		}
		break;

		case IDCANCEL:
			EndDialog( hDlg, TRUE );
			return TRUE;
		}
		return FALSE;

	case WM_CLOSE:
		EndDialog( hDlg, FALSE );
		return TRUE;

	default:
		return FALSE;
	}
}
INT_PTR Dlg_MemBookmark::MemBookmarkDialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	PMEASUREITEMSTRUCT pmis;
	PDRAWITEMSTRUCT pdis;
	int nSelect;
	HWND hList;
	int offset = 2;

	RECT rcBounds, rcLabel;

	switch ( uMsg )
	{
		case WM_INITDIALOG:
		{
			GenerateResizes( hwnd );

			m_hMemBookmarkDialog = hwnd;
			hList = GetDlgItem( m_hMemBookmarkDialog, IDC_RA_LBX_ADDRESSES );

			SetupColumns( hList );

			// Auto-import bookmark file when opening dialog
			if ( g_pCurrentGameData->GetGameID() != 0 )
			{
				std::string file = RA_DIR_BOOKMARKS + std::to_string( g_pCurrentGameData->GetGameID() ) + "-Bookmarks.txt";
				ImportFromFile( file );
			}

			RestoreWindowPosition( hwnd, "Memory Bookmarks", true, false );
			return TRUE;
		}

		case WM_GETMINMAXINFO:
		{
			LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
			lpmmi->ptMinTrackSize = pDlgMemBookmarkMin;
		}
		break;

		case WM_SIZE:
		{
			RARect winRect;
			GetWindowRect( hwnd, &winRect );

			for ( ResizeContent content : vDlgMemBookmarkResize )
				content.Resize( winRect.Width(), winRect.Height() );

			//InvalidateRect( hwnd, NULL, TRUE );
			RememberWindowSize(hwnd, "Memory Bookmarks");
		}
		break;

		case WM_MOVE:
			RememberWindowPosition(hwnd, "Memory Bookmarks");
			break;

		case WM_MEASUREITEM:
			pmis = (PMEASUREITEMSTRUCT)lParam;
			pmis->itemHeight = 16;
			return TRUE;

		case WM_DRAWITEM:
		{
			pdis = (PDRAWITEMSTRUCT)lParam;

			// If there are no list items, skip this message.
			if ( pdis->itemID == -1 )
				break;

			switch ( pdis->itemAction )
			{
				case ODA_SELECT:
				case ODA_DRAWENTIRE:

					hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );

					ListView_GetItemRect( hList, pdis->itemID, &rcBounds, LVIR_BOUNDS );
					ListView_GetItemRect( hList, pdis->itemID, &rcLabel, LVIR_LABEL );
					RECT rcCol ( rcBounds );
					rcCol.right = rcCol.left + ListView_GetColumnWidth( hList, 0 );

					// Draw Item Label - Column 0
					wchar_t buffer[ 512 ];
					if ( m_vBookmarks[ pdis->itemID ]->Decimal() )
						swprintf_s ( buffer, 512, L"(D)%s", m_vBookmarks[ pdis->itemID ]->Description().c_str() );
					else
						swprintf_s ( buffer, 512, L"%s", m_vBookmarks[ pdis->itemID ]->Description().c_str() );

					if ( pdis->itemState & ODS_SELECTED )
					{
						SetTextColor( pdis->hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
						SetBkColor( pdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
						FillRect( pdis->hDC, &rcBounds, GetSysColorBrush( COLOR_HIGHLIGHT ) );
					}
					else
					{
						SetTextColor( pdis->hDC, GetSysColor( COLOR_WINDOWTEXT ) );

						COLORREF color;

						if ( m_vBookmarks[ pdis->itemID ]->Frozen() )
							color = RGB( 255, 255, 160 );
						else
							color = GetSysColor( COLOR_WINDOW );

						HBRUSH hBrush = CreateSolidBrush( color );
						SetBkColor( pdis->hDC, color );
						FillRect( pdis->hDC, &rcBounds, hBrush );
						DeleteObject( hBrush );
					}

					if ( wcslen( buffer ) > 0 )
					{
						rcLabel.left += ( offset / 2 );
						rcLabel.right -= offset;

						DrawTextW( pdis->hDC, buffer, wcslen( buffer ), &rcLabel, DT_SINGLELINE | DT_LEFT | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_END_ELLIPSIS );
					}

					// Draw Item Label for remaining columns
					LV_COLUMN lvc;
					lvc.mask = LVCF_FMT | LVCF_WIDTH;

					for ( size_t i = 1; ListView_GetColumn( hList, i, &lvc ); ++i )
					{
						rcCol.left = rcCol.right;
						rcCol.right += lvc.cx;

						switch ( i )
						{
							case CSI_ADDRESS:
								swprintf_s ( buffer, 512, L"%06x", m_vBookmarks[ pdis->itemID ]->Address() );
								break;
							case CSI_VALUE:
								if ( m_vBookmarks[ pdis->itemID ]->Decimal() )
									swprintf_s ( buffer, 512, L"%u", m_vBookmarks[ pdis->itemID ]->Value() );
								else
								{
									switch ( m_vBookmarks[ pdis->itemID ]->Type() )
									{
										case 1: swprintf_s ( buffer, 512, L"%02x", m_vBookmarks[ pdis->itemID ]->Value() ); break;
										case 2: swprintf_s ( buffer, 512, L"%04x", m_vBookmarks[ pdis->itemID ]->Value() ); break;
										case 3: swprintf_s ( buffer, 512, L"%08x", m_vBookmarks[ pdis->itemID ]->Value() ); break;
									}
								}
								break;
							case CSI_PREVIOUS:
								if ( m_vBookmarks[ pdis->itemID ]->Decimal() )
									swprintf_s ( buffer, 512, L"%u", m_vBookmarks[ pdis->itemID ]->Previous() );
								else
								{
									switch ( m_vBookmarks[ pdis->itemID ]->Type() )
									{
										case 1: swprintf_s ( buffer, 512, L"%02x", m_vBookmarks[ pdis->itemID ]->Previous() ); break;
										case 2: swprintf_s ( buffer, 512, L"%04x", m_vBookmarks[ pdis->itemID ]->Previous() ); break;
										case 3: swprintf_s ( buffer, 512, L"%08x", m_vBookmarks[ pdis->itemID ]->Previous() ); break;
									}
								}
								break;
							case CSI_CHANGES:
								swprintf_s ( buffer, 512, L"%d", m_vBookmarks[ pdis->itemID ]->Count() );
								break;
							default:
								swprintf_s ( buffer, 512, L"" );
								break;
						}

						if ( wcslen( buffer ) == 0 )
							continue;

						UINT nJustify = DT_LEFT;
						switch ( lvc.fmt & LVCFMT_JUSTIFYMASK )
						{
							case LVCFMT_RIGHT:
								nJustify = DT_RIGHT;
								break;
							case LVCFMT_CENTER:
								nJustify = DT_CENTER;
								break;
							default:
								break;
						}

						rcLabel = rcCol;
						rcLabel.left += offset;
						rcLabel.right -= offset;

						DrawTextW( pdis->hDC, buffer, wcslen( buffer ), &rcLabel, nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS );
					}

					//if (pdis->itemState & ODS_SELECTED) //&& (GetFocus() == this)
					//	DrawFocusRect(pdis->hDC, &rcBounds);

					break;

				case ODA_FOCUS:
					break;
			}
			return TRUE;
		}

		case WM_NOTIFY:
		{
			switch ( LOWORD( wParam ) )
			{
				case IDC_RA_LBX_ADDRESSES:
					if ( ( (LPNMHDR)lParam )->code == NM_CLICK )
					{
						hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );

						nSelect = ListView_GetNextItem( hList, -1, LVNI_FOCUSED );

						if ( nSelect == -1 )
							break;
					}
					else if ( ( (LPNMHDR)lParam )->code == NM_DBLCLK )
					{
						hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );

						LPNMITEMACTIVATE pOnClick = (LPNMITEMACTIVATE)lParam;

						if ( pOnClick->iItem != -1 && pOnClick->iSubItem == CSI_DESC )
						{
							nSelItemBM = pOnClick->iItem;
							nSelSubItemBM = pOnClick->iSubItem;

							EditLabel ( pOnClick->iItem, pOnClick->iSubItem );
						}
						else if ( pOnClick->iItem != -1 && pOnClick->iSubItem == CSI_ADDRESS )
						{
							g_MemoryDialog.SetWatchingAddress( m_vBookmarks[ pOnClick->iItem ]->Address() );
							MemoryViewerControl::setAddress( ( m_vBookmarks[ pOnClick->iItem ]->Address() & 
								~( 0xf ) ) - ( (int)( MemoryViewerControl::m_nDisplayedLines / 2 ) << 4 ) + ( 0x50 ) );
						}
					}
			}
			return TRUE;
		}
		case WM_COMMAND:
		{
			switch ( LOWORD( wParam ) )
			{
				case IDOK:
				case IDCLOSE:
				case IDCANCEL:
					EndDialog( hwnd, true );
					return TRUE;

				case IDC_RA_ADD_BOOKMARK:
				{
					if ( g_MemoryDialog.GetHWND() != nullptr )
						AddAddress();

					return TRUE;
				}
				case IDC_RA_DEL_BOOKMARK:
				{
					HWND hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );
					int nSel = ListView_GetNextItem( hList, -1, LVNI_SELECTED );

					if ( nSel != -1 )
					{
						while ( nSel >= 0 )
						{
							MemBookmark* pBookmark = m_vBookmarks[ nSel ];

							// Remove from vector
							m_vBookmarks.erase( m_vBookmarks.begin() + nSel );

							// Remove from map
							std::vector<const MemBookmark*> *pVector;
							pVector = &m_BookmarkMap.find( pBookmark->Address() )->second;
							pVector->erase( std::find( pVector->begin(), pVector->end(), pBookmark ) );
							if ( pVector->size() == 0 )
								m_BookmarkMap.erase( pBookmark->Address() );

							delete pBookmark;

							ListView_DeleteItem( hList, nSel );

							nSel = ListView_GetNextItem( hList, -1, LVNI_SELECTED );
						}

						InvalidateRect( hList, NULL, FALSE );
					}

					return TRUE;
				}
				case IDC_RA_FREEZE:
				{
					if ( m_vBookmarks.size() > 0 )
					{
						hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );
						unsigned int uSelectedCount = ListView_GetSelectedCount( hList );

						if ( uSelectedCount > 0 )
						{
							for ( int i = ListView_GetNextItem( hList, -1, LVNI_SELECTED ); i >= 0; i = ListView_GetNextItem( hList, i, LVNI_SELECTED ) )
								m_vBookmarks[ i ]->SetFrozen( !m_vBookmarks[ i ]->Frozen() );
						}
						ListView_SetItemState( hList, -1, LVIF_STATE, LVIS_SELECTED );
					}
					return TRUE;
				}
				case IDC_RA_CLEAR_CHANGE:
				{
					if ( m_vBookmarks.size() > 0 )
					{
						hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );
						int idx = -1;
						for ( MemBookmark* bookmark : m_vBookmarks )
						{
							idx++;

							bookmark->ResetCount();
						}
						
						InvalidateRect( hList, NULL, FALSE );
					}

					return TRUE;
				}
				case IDC_RA_DECIMALBOOKMARK:
				{
					if ( m_vBookmarks.size() > 0 )
					{
						hList = GetDlgItem( hwnd, IDC_RA_LBX_ADDRESSES );
						unsigned int uSelectedCount = ListView_GetSelectedCount( hList );

						if ( uSelectedCount > 0 )
						{
							for ( int i = ListView_GetNextItem( hList, -1, LVNI_SELECTED ); i >= 0; i = ListView_GetNextItem( hList, i, LVNI_SELECTED ) )
								m_vBookmarks[ i ]->SetDecimal( !m_vBookmarks[ i ]->Decimal() );
						}
						ListView_SetItemState( hList, -1, LVIF_STATE, LVIS_SELECTED );
					}
					return TRUE;
				}
				case IDC_RA_SAVEBOOKMARK:
				{
					ExportJSON();
					return TRUE;
				}
				case IDC_RA_LOADBOOKMARK:
				{
					std::string file = ImportDialog();
					if (file.length() > 0 )
						ImportFromFile( file );
					return TRUE;
				}
				default:
					return FALSE;
			}
		}
		default:
			break;
	}

	return FALSE;
}