window-basic-main.cpp 11.4 KB
Newer Older
1 2 3 4 5
/******************************************************************************
    Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>

    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
6
    the Free Software Foundation, either version 2 of the License, or
7 8 9
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 12 13 14 15 16 17
    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, see <http://www.gnu.org/licenses/>.
******************************************************************************/

J
jp9000 已提交
18 19
#include <obs.hpp>

20 21
#include <wx/msgdlg.h>

22
#include "obs-app.hpp"
J
jp9000 已提交
23
#include "wx-wrappers.hpp"
24 25
#include "window-basic-settings.hpp"
#include "window-basic-main.hpp"
26
#include "window-namedialog.hpp"
27

28
using namespace std;
J
jp9000 已提交
29

30 31 32 33 34 35 36 37 38 39
obs_scene_t OBSBasic::GetCurrentScene()
{
	int sel = scenes->GetSelection();
	if (sel == wxNOT_FOUND)
		return NULL;

	return (obs_scene_t)scenes->GetClientData(sel);
}

void OBSBasic::AddScene(obs_source_t source)
40 41 42
{
	const char *name  = obs_source_getname(source);
	obs_scene_t scene = obs_scene_fromsource(source);
43 44 45 46 47 48 49
	scenes->Append(WX_UTF8(name), scene);

	signal_handler_t handler = obs_source_signalhandler(source);
	signal_handler_connect(handler, "add", OBSBasic::SceneItemAdded,
			this);
	signal_handler_connect(handler, "remove", OBSBasic::SceneItemRemoved,
			this);
50 51
}

52
void OBSBasic::RemoveScene(obs_source_t source)
J
jp9000 已提交
53 54 55
{
	const char *name = obs_source_getname(source);

56 57 58 59 60 61 62 63 64 65 66 67 68 69
	int idx = scenes->FindString(name);
	if (idx != wxNOT_FOUND)
		scenes->Delete(idx);
}

void OBSBasic::AddSceneItem(obs_sceneitem_t item)
{
	obs_source_t source = obs_sceneitem_getsource(item);
	const char *name = obs_source_getname(source);
	sources->Insert(WX_UTF8(name), 0, item);
}

void OBSBasic::RemoveSceneItem(obs_sceneitem_t item)
{
70 71 72
	for (unsigned int idx = 0; idx < sources->GetCount(); idx++) {
		obs_sceneitem_t curItem;
		curItem = (obs_sceneitem_t)sources->GetClientData(idx);
73

74 75 76 77 78
		if (item == curItem) {
			sources->Delete(idx);
			break;
		}
	}
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
}

void OBSBasic::UpdateSources(obs_scene_t scene)
{
	sources->Clear();

	obs_scene_enum_items(scene,
			[] (obs_scene_t scene, obs_sceneitem_t item, void *p)
			{
				OBSBasic *window = static_cast<OBSBasic*>(p);
				window->AddSceneItem(item);
				return true;
			}, this);
}

void OBSBasic::UpdateSceneSelection(obs_source_t source)
{
	if (source) {
		obs_source_type type;
		obs_source_gettype(source, &type, NULL);

		if (type == SOURCE_SCENE) {
			obs_scene_t scene = obs_scene_fromsource(source);
			const char *name = obs_source_getname(source);
			int idx = scenes->FindString(WX_UTF8(name));
			int sel = scenes->GetSelection();

			if (idx != sel) {
				scenes->SetSelection(idx);
				UpdateSources(scene);
			}
		}
	} else {
		scenes->SetSelection(wxNOT_FOUND);
J
jp9000 已提交
113
	}
114 115 116 117 118 119 120 121 122 123
}

/* OBS Callbacks */

void OBSBasic::SceneItemAdded(void *data, calldata_t params)
{
	OBSBasic *window = static_cast<OBSBasic*>(data);

	obs_scene_t scene = (obs_scene_t)calldata_ptr(params, "scene");
	obs_sceneitem_t item = (obs_sceneitem_t)calldata_ptr(params, "item");
J
jp9000 已提交
124

125 126
	if (window->GetCurrentScene() == scene)
		window->AddSceneItem(item);
J
jp9000 已提交
127 128
}

129
void OBSBasic::SceneItemRemoved(void *data, calldata_t params)
130
{
131
	OBSBasic *window = static_cast<OBSBasic*>(data);
132

133 134 135 136
	obs_scene_t scene = (obs_scene_t)calldata_ptr(params, "scene");
	obs_sceneitem_t item = (obs_sceneitem_t)calldata_ptr(params, "item");

	if (window->GetCurrentScene() == scene)
J
jp9000 已提交
137
		window->RemoveSceneItem(item);
138 139 140 141 142
}

void OBSBasic::SourceAdded(void *data, calldata_t params)
{
	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
143 144 145 146 147

	obs_source_type type;
	obs_source_gettype(source, &type, NULL);

	if (type == SOURCE_SCENE)
148
		static_cast<OBSBasic*>(data)->AddScene(source);
149 150 151 152
}

void OBSBasic::SourceDestroyed(void *data, calldata_t params)
{
153
	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
154

J
jp9000 已提交
155 156 157 158
	obs_source_type type;
	obs_source_gettype(source, &type, NULL);

	if (type == SOURCE_SCENE)
159
		static_cast<OBSBasic*>(data)->RemoveScene(source);
160 161
}

162 163 164 165 166 167 168 169 170 171 172
void OBSBasic::ChannelChanged(void *data, calldata_t params)
{
	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
	uint32_t channel = calldata_uint32(params, "channel");

	if (channel == 0)
		static_cast<OBSBasic*>(data)->UpdateSceneSelection(source);
}

/* Main class functions */

J
jp9000 已提交
173 174 175 176 177 178 179
bool OBSBasic::Init()
{
	if (!obs_startup())
		return false;
	if (!InitGraphics())
		return false;

180 181 182 183
	signal_handler_connect(obs_signalhandler(), "source-add",
			OBSBasic::SourceAdded, this);
	signal_handler_connect(obs_signalhandler(), "source-destroy",
			OBSBasic::SourceDestroyed, this);
184 185
	signal_handler_connect(obs_signalhandler(), "channel-change",
			OBSBasic::ChannelChanged, this);
186

187 188
	/* TODO: this is a test */
	obs_load_module("test-input");
189

J
jp9000 已提交
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
	return true;
}

OBSBasic::~OBSBasic()
{
	obs_shutdown();
}

bool OBSBasic::InitGraphics()
{
	struct obs_video_info ovi;
	wxGetApp().GetConfigFPS(ovi.fps_num, ovi.fps_den);
	ovi.graphics_module = wxGetApp().GetRenderModule();
	ovi.base_width    = (uint32_t)config_get_uint(GetGlobalConfig(),
			"Video", "BaseCX");
	ovi.base_height   = (uint32_t)config_get_uint(GetGlobalConfig(),
			"Video", "BaseCY");
	ovi.output_width  = (uint32_t)config_get_uint(GetGlobalConfig(),
			"Video", "OutputCX");
	ovi.output_height = (uint32_t)config_get_uint(GetGlobalConfig(),
			"Video", "OutputCY");
	ovi.output_format = VIDEO_FORMAT_RGBA;
	ovi.adapter       = 0;
	ovi.window        = WxToGSWindow(previewPanel);

	//required to make opengl display stuff on osx(?)
J
jp9000 已提交
216
	ResizePreview(ovi.base_width, ovi.base_height);
J
jp9000 已提交
217 218
	SendSizeEvent();

219
	wxSize size = previewPanel->GetClientSize();
J
jp9000 已提交
220 221 222 223 224 225
	ovi.window_width  = size.x;
	ovi.window_height = size.y;

	if (!obs_reset_video(&ovi))
		return false;

J
jp9000 已提交
226 227 228
	return true;
}

229
void OBSBasic::OnClose(wxCloseEvent &event)
230 231
{
	wxGetApp().ExitMainLoop();
232 233 234
	event.Skip();
}

235
void OBSBasic::OnMinimize(wxIconizeEvent &event)
236 237 238 239
{
	event.Skip();
}

J
jp9000 已提交
240
void OBSBasic::ResizePreview(uint32_t cx, uint32_t cy)
241
{
242
	/* resize preview panel to fix to the top section of the window */
243 244
	wxSize targetSize   = GetPreviewContainer()->GetSize();
	double targetAspect = double(targetSize.x) / double(targetSize.y);
J
jp9000 已提交
245
	double baseAspect   = double(cx) / double(cy);
246
	wxSize newSize;
247 248

	if (targetAspect > baseAspect)
249
		newSize = wxSize(targetSize.y * baseAspect, targetSize.y);
250
	else
251 252 253
		newSize = wxSize(targetSize.x, targetSize.x / baseAspect);

	GetPreviewPanel()->SetMinSize(newSize);
J
jp9000 已提交
254 255 256 257 258 259 260 261 262 263 264 265
}

void OBSBasic::OnSize(wxSizeEvent &event)
{
	struct obs_video_info ovi;

	event.Skip();

	if (!obs_get_video_info(&ovi))
		return;

	ResizePreview(ovi.base_width, ovi.base_height);
266 267 268 269 270 271
}

void OBSBasic::OnResizePreview(wxSizeEvent &event)
{
	event.Skip();

272
	wxSize newSize = previewPanel->GetClientSize();
J
jp9000 已提交
273

274 275 276 277 278 279
	graphics_t graphics = obs_graphics();
	if (graphics) {
		gs_entercontext(graphics);
		gs_resize(newSize.x, newSize.y);
		gs_leavecontext();
	}
280 281
}

282
void OBSBasic::fileNewClicked(wxCommandEvent &event)
283 284 285
{
}

286
void OBSBasic::fileOpenClicked(wxCommandEvent &event)
287 288 289
{
}

290
void OBSBasic::fileSaveClicked(wxCommandEvent &event)
291 292 293
{
}

294
void OBSBasic::fileExitClicked(wxCommandEvent &event)
295
{
J
jp9000 已提交
296
	wxGetApp().ExitMainLoop();
297 298
}

299 300 301 302 303 304 305 306
void OBSBasic::scenesClicked(wxCommandEvent &event)
{
	int sel = scenes->GetSelection();

	obs_source_t source = NULL;
	if (sel != wxNOT_FOUND) {
		obs_scene_t scene = (obs_scene_t)scenes->GetClientData(sel);
		source = obs_scene_getsource(scene);
307
		UpdateSources(scene);
308 309
	}

310
	/* TODO: allow transitions */
311 312 313
	obs_set_output_source(0, source);
}

314
void OBSBasic::scenesRDown(wxMouseEvent &event)
315 316 317
{
}

318
void OBSBasic::sceneAddClicked(wxCommandEvent &event)
319
{
320 321 322 323 324 325 326
	string name;
	int ret = NameDialog::AskForName(this,
			Str("MainWindow.AddSceneDlg.Title"),
			Str("MainWindow.AddSceneDlg.Text"),
			name);

	if (ret == wxID_OK) {
327 328 329 330 331 332 333 334 335 336 337
		obs_source_t source = obs_get_source_by_name(name.c_str());
		if (source) {
			wxMessageBox(WXStr("MainWindow.NameExists.Text"),
			             WXStr("MainWindow.NameExists.Title"),
			             wxOK|wxCENTRE, this);

			obs_source_release(source);
			sceneAddClicked(event);
			return;
		}

338
		obs_scene_t scene = obs_scene_create(name.c_str());
339 340
		source = obs_scene_getsource(scene);
		obs_add_source(source);
341
		obs_scene_release(scene);
342 343

		obs_set_output_source(0, source);
344
	}
345 346
}

347
void OBSBasic::sceneRemoveClicked(wxCommandEvent &event)
348
{
J
jp9000 已提交
349 350 351 352 353 354 355
	int sel = scenes->GetSelection();
	if (sel == wxNOT_FOUND)
		return;

	obs_scene_t scene = (obs_scene_t)scenes->GetClientData(sel);
	obs_source_t source = obs_scene_getsource(scene);
	obs_source_remove(source);
356 357
}

358
void OBSBasic::scenePropertiesClicked(wxCommandEvent &event)
359 360 361
{
}

362
void OBSBasic::sceneUpClicked(wxCommandEvent &event)
363 364 365
{
}

366
void OBSBasic::sceneDownClicked(wxCommandEvent &event)
367 368 369
{
}

370 371 372 373 374 375 376 377
void OBSBasic::sourcesClicked(wxCommandEvent &event)
{
}

void OBSBasic::sourcesToggled(wxCommandEvent &event)
{
}

378
void OBSBasic::sourcesRDown(wxMouseEvent &event)
379 380 381
{
}

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
void OBSBasic::AddSource(obs_scene_t scene, const char *id)
{
	string name;

	bool success = false;
	while (!success) {
		int ret = NameDialog::AskForName(this,
				Str("MainWindow.AddSourceDlg.Title"),
				Str("MainWindow.AddSourceDlg.Text"),
				name);

		if (ret == wxID_CANCEL)
			break;

		obs_source_t source = obs_get_source_by_name(
				name.c_str());
		if (!source) {
			success = true;
		} else {
			wxMessageBox(WXStr("MainWindow.NameExists.Text"),
402 403
			             WXStr("MainWindow.NameExists.Title"),
			             wxOK|wxCENTRE, this);
404 405 406 407 408 409 410 411 412 413 414 415 416
			obs_source_release(source);
		}
	}

	if (success) {
		obs_source_t source = obs_source_create(SOURCE_INPUT, id,
				name.c_str(), NULL);
		obs_add_source(source);
		obs_sceneitem_t item = obs_scene_add(scene, source);
		obs_source_release(source);
	}
}

J
jp9000 已提交
417
void OBSBasic::AddSourcePopupMenu()
418
{
419
	int sceneSel = scenes->GetSelection();
420 421 422 423
	size_t idx = 0;
	const char *type;
	vector<const char *> types;

424 425 426
	if (sceneSel == wxNOT_FOUND)
		return;

427 428 429 430 431 432 433 434 435
	obs_scene_t scene = (obs_scene_t)scenes->GetClientData(sceneSel);
	obs_scene_addref(scene);

	unique_ptr<wxMenu> popup(new wxMenu());
	while (obs_enum_input_types(idx, &type)) {
		const char *name = obs_source_getdisplayname(SOURCE_INPUT,
				type, wxGetApp().GetLocale());

		types.push_back(type);
436
		popup->Append((int)idx+1, wxString(name, wxConvUTF8));
437 438 439 440 441 442 443

		idx++;
	}

	if (idx) {
		int id = WXDoPopupMenu(this, popup.get());
		if (id != -1)
444
			AddSource(scene, types[id-1]);
445 446 447 448 449 450 451
	}

	obs_scene_release(scene);
}

void OBSBasic::sourceAddClicked(wxCommandEvent &event)
{
J
jp9000 已提交
452
	AddSourcePopupMenu();
453 454
}

455
void OBSBasic::sourceRemoveClicked(wxCommandEvent &event)
456
{
J
jp9000 已提交
457 458 459 460 461 462 463 464
	int sel = sources->GetSelection();
	if (sel == wxNOT_FOUND)
		return;

	obs_sceneitem_t item = (obs_sceneitem_t)sources->GetClientData(sel);
	obs_source_t source = obs_sceneitem_getsource(item);
	int ref = obs_sceneitem_destroy(item);

465 466 467
	/* If this is the last reference in the scene, mark the source for
	 * removal.  Reference count being at 1 means that it's no longer in
	 * any more scenes. */
J
jp9000 已提交
468 469
	if (ref == 1)
		obs_source_remove(source);
470 471
}

472
void OBSBasic::sourcePropertiesClicked(wxCommandEvent &event)
473 474 475
{
}

476
void OBSBasic::sourceUpClicked(wxCommandEvent &event)
477 478 479
{
}

480
void OBSBasic::sourceDownClicked(wxCommandEvent &event)
481 482
{
}
J
jp9000 已提交
483

484 485
void OBSBasic::settingsClicked(wxCommandEvent &event)
{
486 487
	OBSBasicSettings test(this);
	test.ShowModal();
488 489 490
}

void OBSBasic::exitClicked(wxCommandEvent &event)
J
jp9000 已提交
491 492 493
{
	wxGetApp().ExitMainLoop();
}