/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * geometry.cpp - Geometry classes tests
 */

#include <iostream>

#include <libcamera/geometry.h>

#include "test.h"

using namespace std;
using namespace libcamera;

class GeometryTest : public Test
{
protected:
	template<typename T>
	bool compare(const T &lhs, const T &rhs,
		     bool (*op)(const T &lhs, const T &rhs),
		     const char *opName, bool expect)
	{
		bool result = op(lhs, rhs);

		if (result != expect) {
			cout << lhs.toString()
			     << opName << " "
			     << rhs.toString()
			     << "test failed" << std::endl;
			return false;
		}

		return true;
	}

	int run()
	{
		/*
		 * Point tests
		 */

		/* Equality */
		if (!compare(Point(50, 100), Point(50, 100), &operator==, "==", true))
			return TestFail;

		if (!compare(Point(-50, 100), Point(-50, 100), &operator==, "==", true))
			return TestFail;

		if (!compare(Point(50, -100), Point(50, -100), &operator==, "==", true))
			return TestFail;

		if (!compare(Point(-50, -100), Point(-50, -100), &operator==, "==", true))
			return TestFail;

		/* Inequality */
		if (!compare(Point(50, 100), Point(50, 100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(-50, 100), Point(-50, 100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(50, -100), Point(50, -100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(-50, -100), Point(-50, -100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(-50, 100), Point(50, 100), &operator!=, "!=", true))
			return TestFail;

		if (!compare(Point(50, -100), Point(50, 100), &operator!=, "!=", true))
			return TestFail;

		if (!compare(Point(-50, -100), Point(50, 100), &operator!=, "!=", true))
			return TestFail;

		/* Negation */
		if (Point(50, 100) != -Point(-50, -100) ||
		    Point(50, 100) == -Point(50, -100) ||
		    Point(50, 100) == -Point(-50, 100)) {
			cout << "Point negation test failed" << endl;
			return TestFail;
		}

		/* Default constructor */
		if (Point() != Point(0, 0)) {
			cout << "Default constructor test failed" << endl;
			return TestFail;
		}

		/*
		 * Size tests
		 */

		if (!Size().isNull() || !Size(0, 0).isNull()) {
			cout << "Null size incorrectly reported as not null" << endl;
			return TestFail;
		}

		if (Size(0, 100).isNull() || Size(100, 0).isNull() || Size(100, 100).isNull()) {
			cout << "Non-null size incorrectly reported as null" << endl;
			return TestFail;
		}

		/* Test alignDownTo(), alignUpTo(), boundTo() and expandTo() */
		Size s(50, 50);

		s.alignDownTo(16, 16);
		if (s != Size(48, 48)) {
			cout << "Size::alignDownTo() test failed" << endl;
			return TestFail;
		}

		s.alignUpTo(32, 32);
		if (s != Size(64, 64)) {
			cout << "Size::alignUpTo() test failed" << endl;
			return TestFail;
		}

		s.boundTo({ 40, 40 });
		if (s != Size(40, 40)) {
			cout << "Size::boundTo() test failed" << endl;
			return TestFail;
		}

		s.expandTo({ 50, 50 });
		if (s != Size(50, 50)) {
			cout << "Size::expandTo() test failed" << endl;
			return TestFail;
		}

		s.alignDownTo(16, 16).alignUpTo(32, 32)
		 .boundTo({ 40, 80 }).expandTo({ 16, 80 });
		if (s != Size(40, 80)) {
			cout << "Size chained in-place modifiers test failed" << endl;
			return TestFail;
		}

		/* Test alignedDownTo(), alignedUpTo(), boundedTo() and expandedTo() */
		if (Size(0, 0).alignedDownTo(16, 8) != Size(0, 0) ||
		    Size(1, 1).alignedDownTo(16, 8) != Size(0, 0) ||
		    Size(16, 8).alignedDownTo(16, 8) != Size(16, 8)) {
			cout << "Size::alignedDownTo() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).alignedUpTo(16, 8) != Size(0, 0) ||
		    Size(1, 1).alignedUpTo(16, 8) != Size(16, 8) ||
		    Size(16, 8).alignedUpTo(16, 8) != Size(16, 8)) {
			cout << "Size::alignedUpTo() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).boundedTo({ 100, 100 }) != Size(0, 0) ||
		    Size(200, 50).boundedTo({ 100, 100 }) != Size(100, 50) ||
		    Size(50, 200).boundedTo({ 100, 100 }) != Size(50, 100)) {
			cout << "Size::boundedTo() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).expandedTo({ 100, 100 }) != Size(100, 100) ||
		    Size(200, 50).expandedTo({ 100, 100 }) != Size(200, 100) ||
		    Size(50, 200).expandedTo({ 100, 100 }) != Size(100, 200)) {
			cout << "Size::expandedTo() test failed" << endl;
			return TestFail;
		}

		/* Aspect ratio tests */
		if (Size(0, 0).boundedToAspectRatio(Size(4, 3)) != Size(0, 0) ||
		    Size(1920, 1440).boundedToAspectRatio(Size(16, 9)) != Size(1920, 1080) ||
		    Size(1920, 1440).boundedToAspectRatio(Size(65536, 36864)) != Size(1920, 1080) ||
		    Size(1440, 1920).boundedToAspectRatio(Size(9, 16)) != Size(1080, 1920) ||
		    Size(1920, 1080).boundedToAspectRatio(Size(4, 3)) != Size(1440, 1080) ||
		    Size(1920, 1080).boundedToAspectRatio(Size(65536, 49152)) != Size(1440, 1080) ||
		    Size(1024, 1024).boundedToAspectRatio(Size(1, 1)) != Size(1024, 1024) ||
		    Size(1920, 1080).boundedToAspectRatio(Size(16, 9)) != Size(1920, 1080) ||
		    Size(200, 100).boundedToAspectRatio(Size(16, 9)) != Size(177, 100) ||
		    Size(300, 200).boundedToAspectRatio(Size(16, 9)) != Size(300, 168)) {
			cout << "Size::boundedToAspectRatio() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).expandedToAspectRatio(Size(4, 3)) != Size(0, 0) ||
		    Size(1920, 1440).expandedToAspectRatio(Size(16, 9)) != Size(2560, 1440) ||
		    Size(1920, 1440).expandedToAspectRatio(Size(65536, 36864)) != Size(2560, 1440) ||
		    Size(1440, 1920).expandedToAspectRatio(Size(9, 16)) != Size(1440, 2560) ||
		    Size(1920, 1080).expandedToAspectRatio(Size(4, 3)) != Size(1920, 1440) ||
		    Size(1920, 1080).expandedToAspectRatio(Size(65536, 49152)) != Size(1920, 1440) ||
		    Size(1024, 1024).expandedToAspectRatio(Size(1, 1)) != Size(1024, 1024) ||
		    Size(1920, 1080).expandedToAspectRatio(Size(16, 9)) != Size(1920, 1080) ||
		    Size(200, 100).expandedToAspectRatio(Size(16, 9)) != Size(200, 112) ||
		    Size(300, 200).expandedToAspectRatio(Size(16, 9)) != Size(355, 200)) {
			cout << "Size::expandedToAspectRatio() test failed" << endl;
			return TestFail;
		}

		/* Size::centeredTo() tests */
		if (Size(0, 0).centeredTo(Point(50, 100)) != Rectangle(50, 100, 0, 0) ||
		    Size(0, 0).centeredTo(Point(-50, -100)) != Rectangle(-50, -100, 0, 0) ||
		    Size(100, 200).centeredTo(Point(50, 100)) != Rectangle(0, 0, 100, 200) ||
		    Size(100, 200).centeredTo(Point(-50, -100)) != Rectangle(-100, -200, 100, 200) ||
		    Size(101, 201).centeredTo(Point(-50, -100)) != Rectangle(-100, -200, 101, 201) ||
		    Size(101, 201).centeredTo(Point(-51, -101)) != Rectangle(-101, -201, 101, 201)) {
			cout << "Size::centeredTo() test failed" << endl;
			return TestFail;
		}

		/* Scale a size by a float */
		if (Size(1000, 2000) * 2.0 != Size(2000, 4000) ||
		    Size(300, 100) * 0.5 != Size(150, 50) ||
		    Size(1, 2) * 1.6 != Size(1, 3)) {
			cout << "Size::operator*() failed" << endl;
			return TestFail;
		}

		if (Size(1000, 2000) / 2.0 != Size(500, 1000) ||
		    Size(300, 100) / 0.5 != Size(600, 200) ||
		    Size(1000, 2000) / 3.0 != Size(333, 666)) {
			cout << "Size::operator*() failed" << endl;
			return TestFail;
		}

		s = Size(300, 100);
		s *= 0.3333;
		if (s != Size(99, 33)) {
			cout << "Size::operator*() test failed" << endl;
			return TestFail;
		}

		s = Size(300, 100);
		s /= 3;
		if (s != Size(100, 33)) {
			cout << "Size::operator*() test failed" << endl;
			return TestFail;
		}

		/* Test Size equality and inequality. */
		if (!compare(Size(100, 100), Size(100, 100), &operator==, "==", true))
			return TestFail;
		if (!compare(Size(100, 100), Size(100, 100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Size(100, 100), Size(200, 100), &operator==, "==", false))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 100), &operator!=, "!=", true))
			return TestFail;

		if (!compare(Size(100, 100), Size(100, 200), &operator==, "==", false))
			return TestFail;
		if (!compare(Size(100, 100), Size(100, 200), &operator!=, "!=", true))
			return TestFail;

		/* Test Size ordering based on combined with and height. */
		if (!compare(Size(100, 100), Size(200, 200), &operator<, "<", true))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 200), &operator<=, "<=", true))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 200), &operator>, ">", false))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 200), &operator>=, ">=", false))
			return TestFail;

		if (!compare(Size(200, 200), Size(100, 100), &operator<, "<", false))
			return TestFail;
		if (!compare(Size(200, 200), Size(100, 100), &operator<=, "<=", false))
			return TestFail;
		if (!compare(Size(200, 200), Size(100, 100), &operator>, ">", true))
			return TestFail;
		if (!compare(Size(200, 200), Size(100, 100), &operator>=, ">=", true))
			return TestFail;

		/* Test Size ordering based on area (with overlapping sizes). */
		if (!compare(Size(200, 100), Size(100, 400), &operator<, "<", true))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 400), &operator<=, "<=", true))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 400), &operator>, ">", false))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 400), &operator>=, ">=", false))
			return TestFail;

		if (!compare(Size(100, 400), Size(200, 100), &operator<, "<", false))
			return TestFail;
		if (!compare(Size(100, 400), Size(200, 100), &operator<=, "<=", false))
			return TestFail;
		if (!compare(Size(100, 400), Size(200, 100), &operator>, ">", true))
			return TestFail;
		if (!compare(Size(100, 400), Size(200, 100), &operator>=, ">=", true))
			return TestFail;

		/* Test Size ordering based on width (with identical areas). */
		if (!compare(Size(100, 200), Size(200, 100), &operator<, "<", true))
			return TestFail;
		if (!compare(Size(100, 200), Size(200, 100), &operator<=, "<=", true))
			return TestFail;
		if (!compare(Size(100, 200), Size(200, 100), &operator>, ">", false))
			return TestFail;
		if (!compare(Size(100, 200), Size(200, 100), &operator>=, ">=", false))
			return TestFail;

		if (!compare(Size(200, 100), Size(100, 200), &operator<, "<", false))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 200), &operator<=, "<=", false))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 200), &operator>, ">", true))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 200), &operator>=, ">=", true))
			return TestFail;

		/*
		 * Rectangle tests
		 */

		/* Test Rectangle::isNull(). */
		if (!Rectangle(0, 0, 0, 0).isNull() ||
		    !Rectangle(1, 1, 0, 0).isNull()) {
			cout << "Null rectangle incorrectly reported as not null" << endl;
			return TestFail;
		}

		if (Rectangle(0, 0, 0, 1).isNull() ||
		    Rectangle(0, 0, 1, 0).isNull() ||
		    Rectangle(0, 0, 1, 1).isNull()) {
			cout << "Non-null rectangle incorrectly reported as null" << endl;
			return TestFail;
		}

		/* Rectangle::size(), Rectangle::topLeft() and Rectangle::center() tests */
		if (Rectangle(-1, -2, 3, 4).size() != Size(3, 4) ||
		    Rectangle(0, 0, 100000, 200000).size() != Size(100000, 200000)) {
			cout << "Rectangle::size() test failed" << endl;
			return TestFail;
		}

		if (Rectangle(1, 2, 3, 4).topLeft() != Point(1, 2) ||
		    Rectangle(-1, -2, 3, 4).topLeft() != Point(-1, -2)) {
			cout << "Rectangle::topLeft() test failed" << endl;
			return TestFail;
		}

		if (Rectangle(0, 0, 300, 400).center() != Point(150, 200) ||
		    Rectangle(-1000, -2000, 300, 400).center() != Point(-850, -1800) ||
		    Rectangle(10, 20, 301, 401).center() != Point(160, 220) ||
		    Rectangle(11, 21, 301, 401).center() != Point(161, 221) ||
		    Rectangle(-1011, -2021, 301, 401).center() != Point(-861, -1821)) {
			cout << "Rectangle::center() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::boundedTo() (intersection function) */
		if (Rectangle(0, 0, 1000, 2000).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(0, 0, 1000, 2000) ||
		    Rectangle(-500, -1000, 1000, 2000).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(0, 0, 500, 1000) ||
		    Rectangle(500, 1000, 1000, 2000).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(500, 1000, 500, 1000) ||
		    Rectangle(300, 400, 50, 100).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(300, 400, 50, 100) ||
		    Rectangle(0, 0, 1000, 2000).boundedTo(Rectangle(300, 400, 50, 100)) !=
			    Rectangle(300, 400, 50, 100) ||
		    Rectangle(0, 0, 100, 100).boundedTo(Rectangle(50, 100, 100, 100)) !=
			    Rectangle(50, 100, 50, 0) ||
		    Rectangle(0, 0, 100, 100).boundedTo(Rectangle(100, 50, 100, 100)) !=
			    Rectangle(100, 50, 0, 50) ||
		    Rectangle(-10, -20, 10, 20).boundedTo(Rectangle(10, 20, 100, 100)) !=
			    Rectangle(10, 20, 0, 0)) {
			cout << "Rectangle::boundedTo() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::enclosedIn() tests */
		if (Rectangle(10, 20, 300, 400).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(10, 20, 300, 400) ||
		    Rectangle(-100, -200, 3000, 4000).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(-10, -20, 1300, 1400) ||
		    Rectangle(-100, -200, 300, 400).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(-10, -20, 300, 400) ||
		    Rectangle(5100, 6200, 300, 400).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(990, 980, 300, 400) ||
		    Rectangle(100, -300, 150, 200).enclosedIn(Rectangle(50, 0, 200, 300)) !=
			    Rectangle(100, 0, 150, 200) ||
		    Rectangle(100, -300, 150, 1200).enclosedIn(Rectangle(50, 0, 200, 300)) !=
			    Rectangle(100, 0, 150, 300) ||
		    Rectangle(-300, 100, 200, 150).enclosedIn(Rectangle(0, 50, 300, 200)) !=
			    Rectangle(0, 100, 200, 150) ||
		    Rectangle(-300, 100, 1200, 150).enclosedIn(Rectangle(0, 50, 300, 200)) !=
			    Rectangle(0, 100, 300, 150)) {
			cout << "Rectangle::enclosedIn() test failed" << endl;
			return TestFail;
		}

		/* Rectange::scaledBy() tests */
		if (Rectangle(10, 20, 300, 400).scaledBy(Size(0, 0), Size(1, 1)) !=
			    Rectangle(0, 0, 0, 0) ||
		    Rectangle(10, -20, 300, 400).scaledBy(Size(32768, 65536), Size(32768, 32768)) !=
			    Rectangle(10, -40, 300, 800) ||
		    Rectangle(-30000, 10000, 20000, 20000).scaledBy(Size(7, 7), Size(7, 7)) !=
			    Rectangle(-30000, 10000, 20000, 20000) ||
		    Rectangle(-20, -30, 320, 240).scaledBy(Size(1280, 960), Size(640, 480)) !=
			    Rectangle(-40, -60, 640, 480) ||
		    Rectangle(1, 1, 2026, 1510).scaledBy(Size(4056, 3024), Size(2028, 1512)) !=
			    Rectangle(2, 2, 4052, 3020)) {
			cout << "Rectangle::scaledBy() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::translatedBy() tests */
		if (Rectangle(10, -20, 300, 400).translatedBy(Point(-30, 40)) !=
			    Rectangle(-20, 20, 300, 400) ||
		    Rectangle(-10, 20, 400, 300).translatedBy(Point(50, -60)) !=
			    Rectangle(40, -40, 400, 300)) {
			cout << "Rectangle::translatedBy() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::scaleBy() tests */
		Rectangle r(-20, -30, 320, 240);
		r.scaleBy(Size(1280, 960), Size(640, 480));
		if (r != Rectangle(-40, -60, 640, 480)) {
			cout << "Rectangle::scaleBy() test failed" << endl;
			return TestFail;
		}

		r = Rectangle(1, 1, 2026, 1510);
		r.scaleBy(Size(4056, 3024), Size(2028, 1512));
		if (r != Rectangle(2, 2, 4052, 3020)) {
			cout << "Rectangle::scaleBy() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::translateBy() tests */
		r = Rectangle(10, -20, 300, 400);
		r.translateBy(Point(-30, 40));
		if (r != Rectangle(-20, 20, 300, 400)) {
			cout << "Rectangle::translateBy() test failed" << endl;
			return TestFail;
		}

		r = Rectangle(-10, 20, 400, 300);
		r.translateBy(Point(50, -60));
		if (r != Rectangle(40, -40, 400, 300)) {
			cout << "Rectangle::translateBy() test failed" << endl;
			return TestFail;
		}

		return TestPass;
	}
};

TEST_REGISTER(GeometryTest)
ref='#n391'>391</a>
<a id='n392' href='#n392'>392</a>
<a id='n393' href='#n393'>393</a>
<a id='n394' href='#n394'>394</a>
<a id='n395' href='#n395'>395</a>
<a id='n396' href='#n396'>396</a>
<a id='n397' href='#n397'>397</a>
<a id='n398' href='#n398'>398</a>
<a id='n399' href='#n399'>399</a>
<a id='n400' href='#n400'>400</a>
<a id='n401' href='#n401'>401</a>
<a id='n402' href='#n402'>402</a>
<a id='n403' href='#n403'>403</a>
<a id='n404' href='#n404'>404</a>
<a id='n405' href='#n405'>405</a>
<a id='n406' href='#n406'>406</a>
<a id='n407' href='#n407'>407</a>
<a id='n408' href='#n408'>408</a>
<a id='n409' href='#n409'>409</a>
<a id='n410' href='#n410'>410</a>
<a id='n411' href='#n411'>411</a>
<a id='n412' href='#n412'>412</a>
<a id='n413' href='#n413'>413</a>
<a id='n414' href='#n414'>414</a>
<a id='n415' href='#n415'>415</a>
<a id='n416' href='#n416'>416</a>
<a id='n417' href='#n417'>417</a>
<a id='n418' href='#n418'>418</a>
<a id='n419' href='#n419'>419</a>
<a id='n420' href='#n420'>420</a>
<a id='n421' href='#n421'>421</a>
<a id='n422' href='#n422'>422</a>
<a id='n423' href='#n423'>423</a>
<a id='n424' href='#n424'>424</a>
<a id='n425' href='#n425'>425</a>
<a id='n426' href='#n426'>426</a>
<a id='n427' href='#n427'>427</a>
<a id='n428' href='#n428'>428</a>
<a id='n429' href='#n429'>429</a>
<a id='n430' href='#n430'>430</a>
<a id='n431' href='#n431'>431</a>
<a id='n432' href='#n432'>432</a>
<a id='n433' href='#n433'>433</a>
<a id='n434' href='#n434'>434</a>
<a id='n435' href='#n435'>435</a>
<a id='n436' href='#n436'>436</a>
<a id='n437' href='#n437'>437</a>
<a id='n438' href='#n438'>438</a>
<a id='n439' href='#n439'>439</a>
<a id='n440' href='#n440'>440</a>
<a id='n441' href='#n441'>441</a>
<a id='n442' href='#n442'>442</a>
<a id='n443' href='#n443'>443</a>
<a id='n444' href='#n444'>444</a>
<a id='n445' href='#n445'>445</a>
<a id='n446' href='#n446'>446</a>
<a id='n447' href='#n447'>447</a>
<a id='n448' href='#n448'>448</a>
<a id='n449' href='#n449'>449</a>
<a id='n450' href='#n450'>450</a>
<a id='n451' href='#n451'>451</a>
<a id='n452' href='#n452'>452</a>
<a id='n453' href='#n453'>453</a>
<a id='n454' href='#n454'>454</a>
<a id='n455' href='#n455'>455</a>
<a id='n456' href='#n456'>456</a>
<a id='n457' href='#n457'>457</a>
<a id='n458' href='#n458'>458</a>
<a id='n459' href='#n459'>459</a>
<a id='n460' href='#n460'>460</a>
<a id='n461' href='#n461'>461</a>
<a id='n462' href='#n462'>462</a>
<a id='n463' href='#n463'>463</a>
<a id='n464' href='#n464'>464</a>
<a id='n465' href='#n465'>465</a>
<a id='n466' href='#n466'>466</a>
<a id='n467' href='#n467'>467</a>
<a id='n468' href='#n468'>468</a>
<a id='n469' href='#n469'>469</a>
<a id='n470' href='#n470'>470</a>
<a id='n471' href='#n471'>471</a>
<a id='n472' href='#n472'>472</a>
<a id='n473' href='#n473'>473</a>
<a id='n474' href='#n474'>474</a>
<a id='n475' href='#n475'>475</a>
<a id='n476' href='#n476'>476</a>
<a id='n477' href='#n477'>477</a>
<a id='n478' href='#n478'>478</a>
<a id='n479' href='#n479'>479</a>
<a id='n480' href='#n480'>480</a>
<a id='n481' href='#n481'>481</a>
<a id='n482' href='#n482'>482</a>
<a id='n483' href='#n483'>483</a>
<a id='n484' href='#n484'>484</a>
<a id='n485' href='#n485'>485</a>
<a id='n486' href='#n486'>486</a>
<a id='n487' href='#n487'>487</a>
<a id='n488' href='#n488'>488</a>
<a id='n489' href='#n489'>489</a>
<a id='n490' href='#n490'>490</a>
<a id='n491' href='#n491'>491</a>
<a id='n492' href='#n492'>492</a>
<a id='n493' href='#n493'>493</a>
<a id='n494' href='#n494'>494</a>
<a id='n495' href='#n495'>495</a>
<a id='n496' href='#n496'>496</a>
<a id='n497' href='#n497'>497</a>
<a id='n498' href='#n498'>498</a>
<a id='n499' href='#n499'>499</a>
<a id='n500' href='#n500'>500</a>
<a id='n501' href='#n501'>501</a>
<a id='n502' href='#n502'>502</a>
<a id='n503' href='#n503'>503</a>
<a id='n504' href='#n504'>504</a>
<a id='n505' href='#n505'>505</a>
<a id='n506' href='#n506'>506</a>
<a id='n507' href='#n507'>507</a>
<a id='n508' href='#n508'>508</a>
<a id='n509' href='#n509'>509</a>
<a id='n510' href='#n510'>510</a>
<a id='n511' href='#n511'>511</a>
<a id='n512' href='#n512'>512</a>
<a id='n513' href='#n513'>513</a>
<a id='n514' href='#n514'>514</a>
<a id='n515' href='#n515'>515</a>
<a id='n516' href='#n516'>516</a>
<a id='n517' href='#n517'>517</a>
<a id='n518' href='#n518'>518</a>
<a id='n519' href='#n519'>519</a>
<a id='n520' href='#n520'>520</a>
<a id='n521' href='#n521'>521</a>
<a id='n522' href='#n522'>522</a>
<a id='n523' href='#n523'>523</a>
<a id='n524' href='#n524'>524</a>
<a id='n525' href='#n525'>525</a>
<a id='n526' href='#n526'>526</a>
<a id='n527' href='#n527'>527</a>
<a id='n528' href='#n528'>528</a>
<a id='n529' href='#n529'>529</a>
<a id='n530' href='#n530'>530</a>
<a id='n531' href='#n531'>531</a>
<a id='n532' href='#n532'>532</a>
<a id='n533' href='#n533'>533</a>
<a id='n534' href='#n534'>534</a>
<a id='n535' href='#n535'>535</a>
<a id='n536' href='#n536'>536</a>
<a id='n537' href='#n537'>537</a>
<a id='n538' href='#n538'>538</a>
<a id='n539' href='#n539'>539</a>
<a id='n540' href='#n540'>540</a>
<a id='n541' href='#n541'>541</a>
<a id='n542' href='#n542'>542</a>
<a id='n543' href='#n543'>543</a>
<a id='n544' href='#n544'>544</a>
<a id='n545' href='#n545'>545</a>
<a id='n546' href='#n546'>546</a>
<a id='n547' href='#n547'>547</a>
<a id='n548' href='#n548'>548</a>
<a id='n549' href='#n549'>549</a>
<a id='n550' href='#n550'>550</a>
<a id='n551' href='#n551'>551</a>
<a id='n552' href='#n552'>552</a>
<a id='n553' href='#n553'>553</a>
<a id='n554' href='#n554'>554</a>
<a id='n555' href='#n555'>555</a>
<a id='n556' href='#n556'>556</a>
<a id='n557' href='#n557'>557</a>
<a id='n558' href='#n558'>558</a>
<a id='n559' href='#n559'>559</a>
<a id='n560' href='#n560'>560</a>
<a id='n561' href='#n561'>561</a>
<a id='n562' href='#n562'>562</a>
<a id='n563' href='#n563'>563</a>
<a id='n564' href='#n564'>564</a>
<a id='n565' href='#n565'>565</a>
<a id='n566' href='#n566'>566</a>
<a id='n567' href='#n567'>567</a>
<a id='n568' href='#n568'>568</a>
<a id='n569' href='#n569'>569</a>
<a id='n570' href='#n570'>570</a>
<a id='n571' href='#n571'>571</a>
<a id='n572' href='#n572'>572</a>
<a id='n573' href='#n573'>573</a>
<a id='n574' href='#n574'>574</a>
<a id='n575' href='#n575'>575</a>
<a id='n576' href='#n576'>576</a>
<a id='n577' href='#n577'>577</a>
<a id='n578' href='#n578'>578</a>
<a id='n579' href='#n579'>579</a>
<a id='n580' href='#n580'>580</a>
<a id='n581' href='#n581'>581</a>
<a id='n582' href='#n582'>582</a>
<a id='n583' href='#n583'>583</a>
<a id='n584' href='#n584'>584</a>
<a id='n585' href='#n585'>585</a>
<a id='n586' href='#n586'>586</a>
<a id='n587' href='#n587'>587</a>
<a id='n588' href='#n588'>588</a>
<a id='n589' href='#n589'>589</a>
<a id='n590' href='#n590'>590</a>
<a id='n591' href='#n591'>591</a>
<a id='n592' href='#n592'>592</a>
<a id='n593' href='#n593'>593</a>
<a id='n594' href='#n594'>594</a>
<a id='n595' href='#n595'>595</a>
<a id='n596' href='#n596'>596</a>
<a id='n597' href='#n597'>597</a>
<a id='n598' href='#n598'>598</a>
<a id='n599' href='#n599'>599</a>
<a id='n600' href='#n600'>600</a>
<a id='n601' href='#n601'>601</a>
<a id='n602' href='#n602'>602</a>
<a id='n603' href='#n603'>603</a>
<a id='n604' href='#n604'>604</a>
<a id='n605' href='#n605'>605</a>
<a id='n606' href='#n606'>606</a>
<a id='n607' href='#n607'>607</a>
<a id='n608' href='#n608'>608</a>
<a id='n609' href='#n609'>609</a>
<a id='n610' href='#n610'>610</a>
<a id='n611' href='#n611'>611</a>
<a id='n612' href='#n612'>612</a>
<a id='n613' href='#n613'>613</a>
<a id='n614' href='#n614'>614</a>
<a id='n615' href='#n615'>615</a>
<a id='n616' href='#n616'>616</a>
<a id='n617' href='#n617'>617</a>
<a id='n618' href='#n618'>618</a>
<a id='n619' href='#n619'>619</a>
<a id='n620' href='#n620'>620</a>
<a id='n621' href='#n621'>621</a>
<a id='n622' href='#n622'>622</a>
<a id='n623' href='#n623'>623</a>
<a id='n624' href='#n624'>624</a>
<a id='n625' href='#n625'>625</a>
<a id='n626' href='#n626'>626</a>
<a id='n627' href='#n627'>627</a>
<a id='n628' href='#n628'>628</a>
<a id='n629' href='#n629'>629</a>
<a id='n630' href='#n630'>630</a>
<a id='n631' href='#n631'>631</a>
<a id='n632' href='#n632'>632</a>
<a id='n633' href='#n633'>633</a>
<a id='n634' href='#n634'>634</a>
<a id='n635' href='#n635'>635</a>
<a id='n636' href='#n636'>636</a>
<a id='n637' href='#n637'>637</a>
<a id='n638' href='#n638'>638</a>
<a id='n639' href='#n639'>639</a>
<a id='n640' href='#n640'>640</a>
<a id='n641' href='#n641'>641</a>
<a id='n642' href='#n642'>642</a>
<a id='n643' href='#n643'>643</a>
<a id='n644' href='#n644'>644</a>
<a id='n645' href='#n645'>645</a>
<a id='n646' href='#n646'>646</a>
<a id='n647' href='#n647'>647</a>
<a id='n648' href='#n648'>648</a>
<a id='n649' href='#n649'>649</a>
<a id='n650' href='#n650'>650</a>
<a id='n651' href='#n651'>651</a>
<a id='n652' href='#n652'>652</a>
<a id='n653' href='#n653'>653</a>
<a id='n654' href='#n654'>654</a>
<a id='n655' href='#n655'>655</a>
<a id='n656' href='#n656'>656</a>
<a id='n657' href='#n657'>657</a>
<a id='n658' href='#n658'>658</a>
<a id='n659' href='#n659'>659</a>
<a id='n660' href='#n660'>660</a>
<a id='n661' href='#n661'>661</a>
<a id='n662' href='#n662'>662</a>
<a id='n663' href='#n663'>663</a>
<a id='n664' href='#n664'>664</a>
<a id='n665' href='#n665'>665</a>
<a id='n666' href='#n666'>666</a>
<a id='n667' href='#n667'>667</a>
<a id='n668' href='#n668'>668</a>
<a id='n669' href='#n669'>669</a>
<a id='n670' href='#n670'>670</a>
<a id='n671' href='#n671'>671</a>
<a id='n672' href='#n672'>672</a>
<a id='n673' href='#n673'>673</a>
<a id='n674' href='#n674'>674</a>
<a id='n675' href='#n675'>675</a>
<a id='n676' href='#n676'>676</a>
<a id='n677' href='#n677'>677</a>
<a id='n678' href='#n678'>678</a>
<a id='n679' href='#n679'>679</a>
<a id='n680' href='#n680'>680</a>
<a id='n681' href='#n681'>681</a>
<a id='n682' href='#n682'>682</a>
<a id='n683' href='#n683'>683</a>
<a id='n684' href='#n684'>684</a>
<a id='n685' href='#n685'>685</a>
<a id='n686' href='#n686'>686</a>
<a id='n687' href='#n687'>687</a>
<a id='n688' href='#n688'>688</a>
<a id='n689' href='#n689'>689</a>
<a id='n690' href='#n690'>690</a>
<a id='n691' href='#n691'>691</a>
<a id='n692' href='#n692'>692</a>
<a id='n693' href='#n693'>693</a>
<a id='n694' href='#n694'>694</a>
<a id='n695' href='#n695'>695</a>
<a id='n696' href='#n696'>696</a>
<a id='n697' href='#n697'>697</a>
<a id='n698' href='#n698'>698</a>
<a id='n699' href='#n699'>699</a>
<a id='n700' href='#n700'>700</a>
<a id='n701' href='#n701'>701</a>
<a id='n702' href='#n702'>702</a>
<a id='n703' href='#n703'>703</a>
<a id='n704' href='#n704'>704</a>
<a id='n705' href='#n705'>705</a>
<a id='n706' href='#n706'>706</a>
<a id='n707' href='#n707'>707</a>
<a id='n708' href='#n708'>708</a>
<a id='n709' href='#n709'>709</a>
<a id='n710' href='#n710'>710</a>
<a id='n711' href='#n711'>711</a>
<a id='n712' href='#n712'>712</a>
<a id='n713' href='#n713'>713</a>
<a id='n714' href='#n714'>714</a>
<a id='n715' href='#n715'>715</a>
<a id='n716' href='#n716'>716</a>
<a id='n717' href='#n717'>717</a>
<a id='n718' href='#n718'>718</a>
<a id='n719' href='#n719'>719</a>
<a id='n720' href='#n720'>720</a>
<a id='n721' href='#n721'>721</a>
<a id='n722' href='#n722'>722</a>
<a id='n723' href='#n723'>723</a>
<a id='n724' href='#n724'>724</a>
<a id='n725' href='#n725'>725</a>
<a id='n726' href='#n726'>726</a>
<a id='n727' href='#n727'>727</a>
<a id='n728' href='#n728'>728</a>
<a id='n729' href='#n729'>729</a>
<a id='n730' href='#n730'>730</a>
<a id='n731' href='#n731'>731</a>
<a id='n732' href='#n732'>732</a>
<a id='n733' href='#n733'>733</a>
<a id='n734' href='#n734'>734</a>
<a id='n735' href='#n735'>735</a>
<a id='n736' href='#n736'>736</a>
<a id='n737' href='#n737'>737</a>
<a id='n738' href='#n738'>738</a>
<a id='n739' href='#n739'>739</a>
<a id='n740' href='#n740'>740</a>
<a id='n741' href='#n741'>741</a>
<a id='n742' href='#n742'>742</a>
<a id='n743' href='#n743'>743</a>
<a id='n744' href='#n744'>744</a>
<a id='n745' href='#n745'>745</a>
<a id='n746' href='#n746'>746</a>
<a id='n747' href='#n747'>747</a>
<a id='n748' href='#n748'>748</a>
<a id='n749' href='#n749'>749</a>
<a id='n750' href='#n750'>750</a>
<a id='n751' href='#n751'>751</a>
<a id='n752' href='#n752'>752</a>
<a id='n753' href='#n753'>753</a>
<a id='n754' href='#n754'>754</a>
<a id='n755' href='#n755'>755</a>
<a id='n756' href='#n756'>756</a>
<a id='n757' href='#n757'>757</a>
<a id='n758' href='#n758'>758</a>
<a id='n759' href='#n759'>759</a>
<a id='n760' href='#n760'>760</a>
<a id='n761' href='#n761'>761</a>
<a id='n762' href='#n762'>762</a>
<a id='n763' href='#n763'>763</a>
<a id='n764' href='#n764'>764</a>
<a id='n765' href='#n765'>765</a>
<a id='n766' href='#n766'>766</a>
<a id='n767' href='#n767'>767</a>
<a id='n768' href='#n768'>768</a>
<a id='n769' href='#n769'>769</a>
<a id='n770' href='#n770'>770</a>
<a id='n771' href='#n771'>771</a>
<a id='n772' href='#n772'>772</a>
<a id='n773' href='#n773'>773</a>
<a id='n774' href='#n774'>774</a>
<a id='n775' href='#n775'>775</a>
<a id='n776' href='#n776'>776</a>
<a id='n777' href='#n777'>777</a>
<a id='n778' href='#n778'>778</a>
<a id='n779' href='#n779'>779</a>
<a id='n780' href='#n780'>780</a>
<a id='n781' href='#n781'>781</a>
<a id='n782' href='#n782'>782</a>
<a id='n783' href='#n783'>783</a>
<a id='n784' href='#n784'>784</a>
<a id='n785' href='#n785'>785</a>
<a id='n786' href='#n786'>786</a>
<a id='n787' href='#n787'>787</a>
<a id='n788' href='#n788'>788</a>
<a id='n789' href='#n789'>789</a>
<a id='n790' href='#n790'>790</a>
</pre></td>
<td class='lines'><pre><code><span class="hl com">/* SPDX-License-Identifier: GPL-2.0-or-later */</span>
<span class="hl com">/*</span>
<span class="hl com"> * Copyright (C) 2019, Google Inc.</span>
<span class="hl com"> *</span>
<span class="hl com"> * main_window.cpp - qcam - Main application window</span>
<span class="hl com"> */</span>

<span class="hl ppc">#include</span> <span class="hl pps">&quot;main_window.h&quot;</span><span class="hl ppc"></span>

<span class="hl ppc">#include &lt;iomanip&gt;</span>
<span class="hl ppc">#include &lt;string&gt;</span>
<span class="hl ppc">#include &lt;sys/mman.h&gt;</span>

<span class="hl ppc">#include &lt;QComboBox&gt;</span>
<span class="hl ppc">#include &lt;QCoreApplication&gt;</span>
<span class="hl ppc">#include &lt;QFileDialog&gt;</span>
<span class="hl ppc">#include &lt;QImage&gt;</span>
<span class="hl ppc">#include &lt;QImageWriter&gt;</span>
<span class="hl ppc">#include &lt;QInputDialog&gt;</span>
<span class="hl ppc">#include &lt;QMutexLocker&gt;</span>
<span class="hl ppc">#include &lt;QStandardPaths&gt;</span>
<span class="hl ppc">#include &lt;QTimer&gt;</span>
<span class="hl ppc">#include &lt;QToolBar&gt;</span>
<span class="hl ppc">#include &lt;QToolButton&gt;</span>
<span class="hl ppc">#include &lt;QtDebug&gt;</span>

<span class="hl ppc">#include &lt;libcamera/camera_manager.h&gt;</span>
<span class="hl ppc">#include &lt;libcamera/version.h&gt;</span>

<span class="hl ppc">#include</span> <span class="hl pps">&quot;dng_writer.h&quot;</span><span class="hl ppc"></span>
<span class="hl ppc">#ifndef QT_NO_OPENGL</span>
<span class="hl ppc">#include</span> <span class="hl pps">&quot;viewfinder_gl.h&quot;</span><span class="hl ppc"></span>
<span class="hl ppc">#endif</span>
<span class="hl ppc">#include</span> <span class="hl pps">&quot;viewfinder_qt.h&quot;</span><span class="hl ppc"></span>

<span class="hl kwa">using namespace</span> libcamera<span class="hl opt">;</span>

<span class="hl ppc">#if QT_VERSION &lt; QT_VERSION_CHECK(5, 14, 0)</span>
<span class="hl com">/*</span>
<span class="hl com"> * Qt::fixed was introduced in v5.14, and ::fixed deprecated in v5.15. Allow</span>
<span class="hl com"> * usage of Qt::fixed unconditionally.</span>
<span class="hl com"> */</span>
<span class="hl kwa">namespace</span> Qt <span class="hl opt">{</span>
<span class="hl kwc">constexpr auto</span> fixed <span class="hl opt">= ::</span>fixed<span class="hl opt">;</span>
<span class="hl opt">}</span> <span class="hl com">/* namespace Qt */</span>
<span class="hl ppc">#endif</span>

<span class="hl com">/**</span>
<span class="hl com"> * \brief Custom QEvent to signal capture completion</span>
<span class="hl com"> */</span>
<span class="hl kwc">class</span> CaptureEvent <span class="hl opt">:</span> <span class="hl kwc">public</span> QEvent
<span class="hl opt">{</span>
<span class="hl kwc">public</span><span class="hl opt">:</span>
	<span class="hl kwd">CaptureEvent</span><span class="hl opt">()</span>
		<span class="hl opt">:</span> <span class="hl kwd">QEvent</span><span class="hl opt">(</span><span class="hl kwd">type</span><span class="hl opt">())</span>
	<span class="hl opt">{</span>
	<span class="hl opt">}</span>

	<span class="hl kwb">static</span> Type <span class="hl kwd">type</span><span class="hl opt">()</span>
	<span class="hl opt">{</span>
		<span class="hl kwb">static int</span> type <span class="hl opt">=</span> <span class="hl kwc">QEvent</span><span class="hl opt">::</span><span class="hl kwd">registerEventType</span><span class="hl opt">();</span>
		<span class="hl kwa">return static_cast</span><span class="hl opt">&lt;</span>Type<span class="hl opt">&gt;(</span>type<span class="hl opt">);</span>
	<span class="hl opt">}</span>
<span class="hl opt">};</span>

<span class="hl com">/**</span>
<span class="hl com"> * \brief Custom QEvent to signal hotplug or unplug</span>
<span class="hl com"> */</span>
<span class="hl kwc">class</span> HotplugEvent <span class="hl opt">:</span> <span class="hl kwc">public</span> QEvent
<span class="hl opt">{</span>
<span class="hl kwc">public</span><span class="hl opt">:</span>
	<span class="hl kwb">enum</span> PlugEvent <span class="hl opt">{</span>
		HotPlug<span class="hl opt">,</span>
		HotUnplug
	<span class="hl opt">};</span>

	<span class="hl kwd">HotplugEvent</span><span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span>shared_ptr<span class="hl opt">&lt;</span>Camera<span class="hl opt">&gt;</span> camera<span class="hl opt">,</span> PlugEvent event<span class="hl opt">)</span>
		<span class="hl opt">:</span> <span class="hl kwd">QEvent</span><span class="hl opt">(</span><span class="hl kwd">type</span><span class="hl opt">()),</span> <span class="hl kwd">camera_</span><span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>camera<span class="hl opt">)),</span> <span class="hl kwd">plugEvent_</span><span class="hl opt">(</span>event<span class="hl opt">)</span>
	<span class="hl opt">{</span>
	<span class="hl opt">}</span>

	<span class="hl kwb">static</span> Type <span class="hl kwd">type</span><span class="hl opt">()</span>
	<span class="hl opt">{</span>
		<span class="hl kwb">static int</span> type <span class="hl opt">=</span> <span class="hl kwc">QEvent</span><span class="hl opt">::</span><span class="hl kwd">registerEventType</span><span class="hl opt">();</span>
		<span class="hl kwa">return static_cast</span><span class="hl opt">&lt;</span>Type<span class="hl opt">&gt;(</span>type<span class="hl opt">);</span>
	<span class="hl opt">}</span>

	PlugEvent <span class="hl kwd">hotplugEvent</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> plugEvent_<span class="hl opt">; }</span>
	Camera <span class="hl opt">*</span><span class="hl kwd">camera</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> camera_<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">(); }</span>

<span class="hl kwc">private</span><span class="hl opt">:</span>
	<span class="hl kwc">std</span><span class="hl opt">::</span>shared_ptr<span class="hl opt">&lt;</span>Camera<span class="hl opt">&gt;</span> camera_<span class="hl opt">;</span>
	PlugEvent plugEvent_<span class="hl opt">;</span>
<span class="hl opt">};</span>

<span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">MainWindow</span><span class="hl opt">(</span>CameraManager <span class="hl opt">*</span>cm<span class="hl opt">,</span> <span class="hl kwb">const</span> <span class="hl kwc">OptionsParser</span><span class="hl opt">::</span>Options <span class="hl opt">&amp;</span>options<span class="hl opt">)</span>
	<span class="hl opt">:</span> <span class="hl kwd">saveRaw_</span><span class="hl opt">(</span><span class="hl kwc">nullptr</span><span class="hl opt">),</span> <span class="hl kwd">options_</span><span class="hl opt">(</span>options<span class="hl opt">),</span> <span class="hl kwd">cm_</span><span class="hl opt">(</span>cm<span class="hl opt">),</span> <span class="hl kwd">allocator_</span><span class="hl opt">(</span><span class="hl kwc">nullptr</span><span class="hl opt">),</span>
	  <span class="hl kwd">isCapturing_</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">),</span> <span class="hl kwd">captureRaw_</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span>
<span class="hl opt">{</span>
	<span class="hl kwb">int</span> ret<span class="hl opt">;</span>

	<span class="hl com">/*</span>
<span class="hl com">	 * Initialize the UI: Create the toolbar, set the window title and</span>
<span class="hl com">	 * create the viewfinder widget.</span>
<span class="hl com">	 */</span>
	<span class="hl kwd">createToolbars</span><span class="hl opt">();</span>

	title_ <span class="hl opt">=</span> <span class="hl str">&quot;QCam &quot;</span> <span class="hl opt">+</span> <span class="hl kwc">QString</span><span class="hl opt">::</span><span class="hl kwd">fromStdString</span><span class="hl opt">(</span><span class="hl kwc">CameraManager</span><span class="hl opt">::</span><span class="hl kwd">version</span><span class="hl opt">());</span>
	<span class="hl kwd">setWindowTitle</span><span class="hl opt">(</span>title_<span class="hl opt">);</span>
	<span class="hl kwd">connect</span><span class="hl opt">(&amp;</span>titleTimer_<span class="hl opt">,</span> <span class="hl kwd">SIGNAL</span><span class="hl opt">(</span><span class="hl kwd">timeout</span><span class="hl opt">()),</span> <span class="hl kwa">this</span><span class="hl opt">,</span> <span class="hl kwd">SLOT</span><span class="hl opt">(</span><span class="hl kwd">updateTitle</span><span class="hl opt">()));</span>

	<span class="hl com">/* Renderer type Qt or GLES, select Qt by default. */</span>
	<span class="hl kwc">std</span><span class="hl opt">::</span>string renderType <span class="hl opt">=</span> <span class="hl str">&quot;qt&quot;</span><span class="hl opt">;</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>options_<span class="hl opt">.</span><span class="hl kwd">isSet</span><span class="hl opt">(</span>OptRenderer<span class="hl opt">))</span>
		renderType <span class="hl opt">=</span> options_<span class="hl opt">[</span>OptRenderer<span class="hl opt">].</span><span class="hl kwd">toString</span><span class="hl opt">();</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>renderType <span class="hl opt">==</span> <span class="hl str">&quot;qt&quot;</span><span class="hl opt">) {</span>
		ViewFinderQt <span class="hl opt">*</span>viewfinder <span class="hl opt">=</span> <span class="hl kwa">new</span> <span class="hl kwd">ViewFinderQt</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">);</span>
		<span class="hl kwd">connect</span><span class="hl opt">(</span>viewfinder<span class="hl opt">, &amp;</span><span class="hl kwc">ViewFinderQt</span><span class="hl opt">::</span>renderComplete<span class="hl opt">,</span>
			<span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>queueRequest<span class="hl opt">);</span>
		viewfinder_ <span class="hl opt">=</span> viewfinder<span class="hl opt">;</span>
		<span class="hl kwd">setCentralWidget</span><span class="hl opt">(</span>viewfinder<span class="hl opt">);</span>
<span class="hl ppc">#ifndef QT_NO_OPENGL</span>
	<span class="hl opt">}</span> <span class="hl kwa">else if</span> <span class="hl opt">(</span>renderType <span class="hl opt">==</span> <span class="hl str">&quot;gles&quot;</span><span class="hl opt">) {</span>
		ViewFinderGL <span class="hl opt">*</span>viewfinder <span class="hl opt">=</span> <span class="hl kwa">new</span> <span class="hl kwd">ViewFinderGL</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">);</span>
		<span class="hl kwd">connect</span><span class="hl opt">(</span>viewfinder<span class="hl opt">, &amp;</span><span class="hl kwc">ViewFinderGL</span><span class="hl opt">::</span>renderComplete<span class="hl opt">,</span>
			<span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>queueRequest<span class="hl opt">);</span>
		viewfinder_ <span class="hl opt">=</span> viewfinder<span class="hl opt">;</span>
		<span class="hl kwd">setCentralWidget</span><span class="hl opt">(</span>viewfinder<span class="hl opt">);</span>
<span class="hl ppc">#endif</span>
	<span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
		<span class="hl kwd">qWarning</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;Invalid render type&quot;</span>
			   <span class="hl opt">&lt;&lt;</span> <span class="hl kwc">QString</span><span class="hl opt">::</span><span class="hl kwd">fromStdString</span><span class="hl opt">(</span>renderType<span class="hl opt">);</span>
		<span class="hl kwd">quit</span><span class="hl opt">();</span>
		<span class="hl kwa">return</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>

	<span class="hl kwd">adjustSize</span><span class="hl opt">();</span>

	<span class="hl com">/* Hotplug/unplug support */</span>
	cm_<span class="hl opt">-&gt;</span>cameraAdded<span class="hl opt">.</span><span class="hl kwd">connect</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>addCamera<span class="hl opt">);</span>
	cm_<span class="hl opt">-&gt;</span>cameraRemoved<span class="hl opt">.</span><span class="hl kwd">connect</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>removeCamera<span class="hl opt">);</span>

	<span class="hl com">/* Open the camera and start capture. */</span>
	ret <span class="hl opt">=</span> <span class="hl kwd">openCamera</span><span class="hl opt">();</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>ret <span class="hl opt">&lt;</span> <span class="hl num">0</span><span class="hl opt">) {</span>
		<span class="hl kwd">quit</span><span class="hl opt">();</span>
		<span class="hl kwa">return</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>

	startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setChecked</span><span class="hl opt">(</span><span class="hl kwa">true</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwc">MainWindow</span><span class="hl opt">::~</span><span class="hl kwd">MainWindow</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">) {</span>
		<span class="hl kwd">stopCapture</span><span class="hl opt">();</span>
		camera_<span class="hl opt">-&gt;</span><span class="hl kwd">release</span><span class="hl opt">();</span>
		camera_<span class="hl opt">.</span><span class="hl kwd">reset</span><span class="hl opt">();</span>
	<span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwb">bool</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">event</span><span class="hl opt">(</span>QEvent <span class="hl opt">*</span>e<span class="hl opt">)</span>
<span class="hl opt">{</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>e<span class="hl opt">-&gt;</span><span class="hl kwd">type</span><span class="hl opt">() ==</span> <span class="hl kwc">CaptureEvent</span><span class="hl opt">::</span><span class="hl kwd">type</span><span class="hl opt">()) {</span>
		<span class="hl kwd">processCapture</span><span class="hl opt">();</span>
		<span class="hl kwa">return true</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">else if</span> <span class="hl opt">(</span>e<span class="hl opt">-&gt;</span><span class="hl kwd">type</span><span class="hl opt">() ==</span> <span class="hl kwc">HotplugEvent</span><span class="hl opt">::</span><span class="hl kwd">type</span><span class="hl opt">()) {</span>
		<span class="hl kwd">processHotplug</span><span class="hl opt">(</span><span class="hl kwa">static_cast</span><span class="hl opt">&lt;</span>HotplugEvent <span class="hl opt">*&gt;(</span>e<span class="hl opt">));</span>
		<span class="hl kwa">return true</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>

	<span class="hl kwa">return</span> <span class="hl kwc">QMainWindow</span><span class="hl opt">::</span><span class="hl kwd">event</span><span class="hl opt">(</span>e<span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwb">int</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">createToolbars</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	QAction <span class="hl opt">*</span>action<span class="hl opt">;</span>

	toolbar_ <span class="hl opt">=</span> <span class="hl kwd">addToolBar</span><span class="hl opt">(</span><span class="hl str">&quot;Main&quot;</span><span class="hl opt">);</span>

	<span class="hl com">/* Disable right click context menu. */</span>
	toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">setContextMenuPolicy</span><span class="hl opt">(</span><span class="hl kwc">Qt</span><span class="hl opt">::</span>PreventContextMenu<span class="hl opt">);</span>

	<span class="hl com">/* Quit action. */</span>
	action <span class="hl opt">=</span> toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">addAction</span><span class="hl opt">(</span><span class="hl kwc">QIcon</span><span class="hl opt">::</span><span class="hl kwd">fromTheme</span><span class="hl opt">(</span><span class="hl str">&quot;application-exit&quot;</span><span class="hl opt">,</span>
						      <span class="hl kwd">QIcon</span><span class="hl opt">(</span><span class="hl str">&quot;:x-circle.svg&quot;</span><span class="hl opt">)),</span>
				     <span class="hl str">&quot;Quit&quot;</span><span class="hl opt">);</span>
	action<span class="hl opt">-&gt;</span><span class="hl kwd">setShortcut</span><span class="hl opt">(</span><span class="hl kwc">Qt</span><span class="hl opt">::</span>CTRL <span class="hl opt">|</span> <span class="hl kwc">Qt</span><span class="hl opt">::</span>Key_Q<span class="hl opt">);</span>
	<span class="hl kwd">connect</span><span class="hl opt">(</span>action<span class="hl opt">, &amp;</span><span class="hl kwc">QAction</span><span class="hl opt">::</span>triggered<span class="hl opt">,</span> <span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>quit<span class="hl opt">);</span>

	<span class="hl com">/* Camera selector. */</span>
	cameraCombo_ <span class="hl opt">=</span> <span class="hl kwa">new</span> <span class="hl kwd">QComboBox</span><span class="hl opt">();</span>
	<span class="hl kwd">connect</span><span class="hl opt">(</span>cameraCombo_<span class="hl opt">,</span> QOverload<span class="hl opt">&lt;</span><span class="hl kwb">int</span><span class="hl opt">&gt;::</span><span class="hl kwd">of</span><span class="hl opt">(&amp;</span><span class="hl kwc">QComboBox</span><span class="hl opt">::</span>activated<span class="hl opt">),</span>
		<span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>switchCamera<span class="hl opt">);</span>

	<span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">const</span> <span class="hl kwc">std</span><span class="hl opt">::</span>shared_ptr<span class="hl opt">&lt;</span>Camera<span class="hl opt">&gt; &amp;</span>cam <span class="hl opt">:</span> cm_<span class="hl opt">-&gt;</span><span class="hl kwd">cameras</span><span class="hl opt">())</span>
		cameraCombo_<span class="hl opt">-&gt;</span><span class="hl kwd">addItem</span><span class="hl opt">(</span><span class="hl kwc">QString</span><span class="hl opt">::</span><span class="hl kwd">fromStdString</span><span class="hl opt">(</span>cam<span class="hl opt">-&gt;</span><span class="hl kwd">id</span><span class="hl opt">()));</span>

	toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">addWidget</span><span class="hl opt">(</span>cameraCombo_<span class="hl opt">);</span>

	toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">addSeparator</span><span class="hl opt">();</span>

	<span class="hl com">/* Start/Stop action. */</span>
	iconPlay_ <span class="hl opt">=</span> <span class="hl kwc">QIcon</span><span class="hl opt">::</span><span class="hl kwd">fromTheme</span><span class="hl opt">(</span><span class="hl str">&quot;media-playback-start&quot;</span><span class="hl opt">,</span>
				     <span class="hl kwd">QIcon</span><span class="hl opt">(</span><span class="hl str">&quot;:play-circle.svg&quot;</span><span class="hl opt">));</span>
	iconStop_ <span class="hl opt">=</span> <span class="hl kwc">QIcon</span><span class="hl opt">::</span><span class="hl kwd">fromTheme</span><span class="hl opt">(</span><span class="hl str">&quot;media-playback-stop&quot;</span><span class="hl opt">,</span>
				     <span class="hl kwd">QIcon</span><span class="hl opt">(</span><span class="hl str">&quot;:stop-circle.svg&quot;</span><span class="hl opt">));</span>

	action <span class="hl opt">=</span> toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">addAction</span><span class="hl opt">(</span>iconPlay_<span class="hl opt">,</span> <span class="hl str">&quot;Start Capture&quot;</span><span class="hl opt">);</span>
	action<span class="hl opt">-&gt;</span><span class="hl kwd">setCheckable</span><span class="hl opt">(</span><span class="hl kwa">true</span><span class="hl opt">);</span>
	action<span class="hl opt">-&gt;</span><span class="hl kwd">setShortcut</span><span class="hl opt">(</span><span class="hl kwc">Qt</span><span class="hl opt">::</span>Key_Space<span class="hl opt">);</span>
	<span class="hl kwd">connect</span><span class="hl opt">(</span>action<span class="hl opt">, &amp;</span><span class="hl kwc">QAction</span><span class="hl opt">::</span>toggled<span class="hl opt">,</span> <span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>toggleCapture<span class="hl opt">);</span>
	startStopAction_ <span class="hl opt">=</span> action<span class="hl opt">;</span>

	<span class="hl com">/* Save As... action. */</span>
	action <span class="hl opt">=</span> toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">addAction</span><span class="hl opt">(</span><span class="hl kwc">QIcon</span><span class="hl opt">::</span><span class="hl kwd">fromTheme</span><span class="hl opt">(</span><span class="hl str">&quot;document-save-as&quot;</span><span class="hl opt">,</span>
						      <span class="hl kwd">QIcon</span><span class="hl opt">(</span><span class="hl str">&quot;:save.svg&quot;</span><span class="hl opt">)),</span>
				     <span class="hl str">&quot;Save As...&quot;</span><span class="hl opt">);</span>
	action<span class="hl opt">-&gt;</span><span class="hl kwd">setShortcut</span><span class="hl opt">(</span><span class="hl kwc">QKeySequence</span><span class="hl opt">::</span>SaveAs<span class="hl opt">);</span>
	<span class="hl kwd">connect</span><span class="hl opt">(</span>action<span class="hl opt">, &amp;</span><span class="hl kwc">QAction</span><span class="hl opt">::</span>triggered<span class="hl opt">,</span> <span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>saveImageAs<span class="hl opt">);</span>

<span class="hl ppc">#ifdef HAVE_DNG</span>
	<span class="hl com">/* Save Raw action. */</span>
	action <span class="hl opt">=</span> toolbar_<span class="hl opt">-&gt;</span><span class="hl kwd">addAction</span><span class="hl opt">(</span><span class="hl kwc">QIcon</span><span class="hl opt">::</span><span class="hl kwd">fromTheme</span><span class="hl opt">(</span><span class="hl str">&quot;camera-photo&quot;</span><span class="hl opt">,</span>
						      <span class="hl kwd">QIcon</span><span class="hl opt">(</span><span class="hl str">&quot;:aperture.svg&quot;</span><span class="hl opt">)),</span>
				     <span class="hl str">&quot;Save Raw&quot;</span><span class="hl opt">);</span>
	action<span class="hl opt">-&gt;</span><span class="hl kwd">setEnabled</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">);</span>
	<span class="hl kwd">connect</span><span class="hl opt">(</span>action<span class="hl opt">, &amp;</span><span class="hl kwc">QAction</span><span class="hl opt">::</span>triggered<span class="hl opt">,</span> <span class="hl kwa">this</span><span class="hl opt">, &amp;</span><span class="hl kwc">MainWindow</span><span class="hl opt">::</span>captureRaw<span class="hl opt">);</span>
	saveRaw_ <span class="hl opt">=</span> action<span class="hl opt">;</span>
<span class="hl ppc">#endif</span>

	<span class="hl kwa">return</span> <span class="hl num">0</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwb">void</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">quit</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	<span class="hl kwc">QTimer</span><span class="hl opt">::</span><span class="hl kwd">singleShot</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">,</span> <span class="hl kwc">QCoreApplication</span><span class="hl opt">::</span><span class="hl kwd">instance</span><span class="hl opt">(),</span>
			   <span class="hl opt">&amp;</span><span class="hl kwc">QCoreApplication</span><span class="hl opt">::</span>quit<span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwb">void</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">updateTitle</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	<span class="hl com">/* Calculate the average frame rate over the last period. */</span>
	<span class="hl kwb">unsigned int</span> duration <span class="hl opt">=</span> frameRateInterval_<span class="hl opt">.</span><span class="hl kwd">elapsed</span><span class="hl opt">();</span>
	<span class="hl kwb">unsigned int</span> frames <span class="hl opt">=</span> framesCaptured_ <span class="hl opt">-</span> previousFrames_<span class="hl opt">;</span>
	<span class="hl kwb">double</span> fps <span class="hl opt">=</span> frames <span class="hl opt">*</span> <span class="hl num">1000.0</span> <span class="hl opt">/</span> duration<span class="hl opt">;</span>

	<span class="hl com">/* Restart counters. */</span>
	frameRateInterval_<span class="hl opt">.</span><span class="hl kwd">start</span><span class="hl opt">();</span>
	previousFrames_ <span class="hl opt">=</span> framesCaptured_<span class="hl opt">;</span>

	<span class="hl kwd">setWindowTitle</span><span class="hl opt">(</span>title_ <span class="hl opt">+</span> <span class="hl str">&quot; : &quot;</span> <span class="hl opt">+</span> <span class="hl kwc">QString</span><span class="hl opt">::</span><span class="hl kwd">number</span><span class="hl opt">(</span>fps<span class="hl opt">,</span> <span class="hl str">&apos;f&apos;</span><span class="hl opt">,</span> <span class="hl num">2</span><span class="hl opt">) +</span> <span class="hl str">&quot; fps&quot;</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl com">/* -----------------------------------------------------------------------------</span>
<span class="hl com"> * Camera Selection</span>
<span class="hl com"> */</span>

<span class="hl kwb">void</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">switchCamera</span><span class="hl opt">(</span><span class="hl kwb">int</span> index<span class="hl opt">)</span>
<span class="hl opt">{</span>
	<span class="hl com">/* Get and acquire the new camera. */</span>
	<span class="hl kwb">const</span> <span class="hl kwc">auto</span> <span class="hl opt">&amp;</span>cameras <span class="hl opt">=</span> cm_<span class="hl opt">-&gt;</span><span class="hl kwd">cameras</span><span class="hl opt">();</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwa">static_cast</span><span class="hl opt">&lt;</span><span class="hl kwb">unsigned int</span><span class="hl opt">&gt;(</span>index<span class="hl opt">) &gt;=</span> cameras<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">())</span>
		<span class="hl kwa">return</span><span class="hl opt">;</span>

	<span class="hl kwb">const</span> <span class="hl kwc">std</span><span class="hl opt">::</span>shared_ptr<span class="hl opt">&lt;</span>Camera<span class="hl opt">&gt; &amp;</span>cam <span class="hl opt">=</span> cameras<span class="hl opt">[</span>index<span class="hl opt">];</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>cam<span class="hl opt">-&gt;</span><span class="hl kwd">acquire</span><span class="hl opt">()) {</span>
		<span class="hl kwd">qInfo</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;Failed to acquire camera&quot;</span> <span class="hl opt">&lt;&lt;</span> cam<span class="hl opt">-&gt;</span><span class="hl kwd">id</span><span class="hl opt">().</span><span class="hl kwd">c_str</span><span class="hl opt">();</span>
		<span class="hl kwa">return</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>

	<span class="hl kwd">qInfo</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;Switching to camera&quot;</span> <span class="hl opt">&lt;&lt;</span> cam<span class="hl opt">-&gt;</span><span class="hl kwd">id</span><span class="hl opt">().</span><span class="hl kwd">c_str</span><span class="hl opt">();</span>

	<span class="hl com">/*</span>
<span class="hl com">	 * Stop the capture session, release the current camera, replace it with</span>
<span class="hl com">	 * the new camera and start a new capture session.</span>
<span class="hl com">	 */</span>
	startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setChecked</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">);</span>

	camera_<span class="hl opt">-&gt;</span><span class="hl kwd">release</span><span class="hl opt">();</span>
	camera_ <span class="hl opt">=</span> cam<span class="hl opt">;</span>

	startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setChecked</span><span class="hl opt">(</span><span class="hl kwa">true</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwc">std</span><span class="hl opt">::</span>string <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">chooseCamera</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	QStringList cameras<span class="hl opt">;</span>
	<span class="hl kwb">bool</span> result<span class="hl opt">;</span>

	<span class="hl com">/* If only one camera is available, use it automatically. */</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>cm_<span class="hl opt">-&gt;</span><span class="hl kwd">cameras</span><span class="hl opt">().</span><span class="hl kwd">size</span><span class="hl opt">() ==</span> <span class="hl num">1</span><span class="hl opt">)</span>
		<span class="hl kwa">return</span> cm_<span class="hl opt">-&gt;</span><span class="hl kwd">cameras</span><span class="hl opt">()[</span><span class="hl num">0</span><span class="hl opt">]-&gt;</span><span class="hl kwd">id</span><span class="hl opt">();</span>

	<span class="hl com">/* Present a dialog box to pick a camera. */</span>
	<span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">const</span> <span class="hl kwc">std</span><span class="hl opt">::</span>shared_ptr<span class="hl opt">&lt;</span>Camera<span class="hl opt">&gt; &amp;</span>cam <span class="hl opt">:</span> cm_<span class="hl opt">-&gt;</span><span class="hl kwd">cameras</span><span class="hl opt">())</span>
		cameras<span class="hl opt">.</span><span class="hl kwd">append</span><span class="hl opt">(</span><span class="hl kwc">QString</span><span class="hl opt">::</span><span class="hl kwd">fromStdString</span><span class="hl opt">(</span>cam<span class="hl opt">-&gt;</span><span class="hl kwd">id</span><span class="hl opt">()));</span>

	QString id <span class="hl opt">=</span> <span class="hl kwc">QInputDialog</span><span class="hl opt">::</span><span class="hl kwd">getItem</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">,</span> <span class="hl str">&quot;Select Camera&quot;</span><span class="hl opt">,</span>
					   <span class="hl str">&quot;Camera:&quot;</span><span class="hl opt">,</span> cameras<span class="hl opt">,</span> <span class="hl num">0</span><span class="hl opt">,</span>
					   <span class="hl kwa">false</span><span class="hl opt">, &amp;</span>result<span class="hl opt">);</span>
	<span class="hl kwa">if</span> <span class="hl opt">(!</span>result<span class="hl opt">)</span>
		<span class="hl kwa">return</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">string</span><span class="hl opt">();</span>

	<span class="hl kwa">return</span> id<span class="hl opt">.</span><span class="hl kwd">toStdString</span><span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwb">int</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">openCamera</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	<span class="hl kwc">std</span><span class="hl opt">::</span>string cameraName<span class="hl opt">;</span>

	<span class="hl com">/*</span>
<span class="hl com">	 * Use the camera specified on the command line, if any, or display the</span>
<span class="hl com">	 * camera selection dialog box otherwise.</span>
<span class="hl com">	 */</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>options_<span class="hl opt">.</span><span class="hl kwd">isSet</span><span class="hl opt">(</span>OptCamera<span class="hl opt">))</span>
		cameraName <span class="hl opt">=</span> <span class="hl kwa">static_cast</span><span class="hl opt">&lt;</span><span class="hl kwc">std</span><span class="hl opt">::</span>string<span class="hl opt">&gt;(</span>options_<span class="hl opt">[</span>OptCamera<span class="hl opt">]);</span>
	<span class="hl kwa">else</span>
		cameraName <span class="hl opt">=</span> <span class="hl kwd">chooseCamera</span><span class="hl opt">();</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>cameraName <span class="hl opt">==</span> <span class="hl str">&quot;&quot;</span><span class="hl opt">)</span>
		<span class="hl kwa">return</span> <span class="hl opt">-</span>EINVAL<span class="hl opt">;</span>

	<span class="hl com">/* Get and acquire the camera. */</span>
	camera_ <span class="hl opt">=</span> cm_<span class="hl opt">-&gt;</span><span class="hl kwd">get</span><span class="hl opt">(</span>cameraName<span class="hl opt">);</span>
	<span class="hl kwa">if</span> <span class="hl opt">(!</span>camera_<span class="hl opt">) {</span>
		<span class="hl kwd">qInfo</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;Camera&quot;</span> <span class="hl opt">&lt;&lt;</span> cameraName<span class="hl opt">.</span><span class="hl kwd">c_str</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;not found&quot;</span><span class="hl opt">;</span>
		<span class="hl kwa">return</span> <span class="hl opt">-</span>ENODEV<span class="hl opt">;</span>
	<span class="hl opt">}</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">-&gt;</span><span class="hl kwd">acquire</span><span class="hl opt">()) {</span>
		<span class="hl kwd">qInfo</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;Failed to acquire camera&quot;</span><span class="hl opt">;</span>
		camera_<span class="hl opt">.</span><span class="hl kwd">reset</span><span class="hl opt">();</span>
		<span class="hl kwa">return</span> <span class="hl opt">-</span>EBUSY<span class="hl opt">;</span>
	<span class="hl opt">}</span>

	<span class="hl com">/* Set the combo-box entry with the currently selected Camera. */</span>
	cameraCombo_<span class="hl opt">-&gt;</span><span class="hl kwd">setCurrentText</span><span class="hl opt">(</span><span class="hl kwc">QString</span><span class="hl opt">::</span><span class="hl kwd">fromStdString</span><span class="hl opt">(</span>cameraName<span class="hl opt">));</span>

	<span class="hl kwa">return</span> <span class="hl num">0</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl com">/* -----------------------------------------------------------------------------</span>
<span class="hl com"> * Capture Start &amp; Stop</span>
<span class="hl com"> */</span>

<span class="hl kwb">void</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">toggleCapture</span><span class="hl opt">(</span><span class="hl kwb">bool</span> start<span class="hl opt">)</span>
<span class="hl opt">{</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>start<span class="hl opt">) {</span>
		<span class="hl kwd">startCapture</span><span class="hl opt">();</span>
		startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setIcon</span><span class="hl opt">(</span>iconStop_<span class="hl opt">);</span>
		startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setText</span><span class="hl opt">(</span><span class="hl str">&quot;Stop Capture&quot;</span><span class="hl opt">);</span>
	<span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
		<span class="hl kwd">stopCapture</span><span class="hl opt">();</span>
		startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setIcon</span><span class="hl opt">(</span>iconPlay_<span class="hl opt">);</span>
		startStopAction_<span class="hl opt">-&gt;</span><span class="hl kwd">setText</span><span class="hl opt">(</span><span class="hl str">&quot;Start Capture&quot;</span><span class="hl opt">);</span>
	<span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl com">/**</span>
<span class="hl com"> * \brief Start capture with the current camera</span>
<span class="hl com"> *</span>
<span class="hl com"> * This function shall not be called directly, use toggleCapture() instead.</span>
<span class="hl com"> */</span>
<span class="hl kwb">int</span> <span class="hl kwc">MainWindow</span><span class="hl opt">::</span><span class="hl kwd">startCapture</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	StreamRoles roles <span class="hl opt">=</span> <span class="hl kwc">StreamKeyValueParser</span><span class="hl opt">::</span><span class="hl kwd">roles</span><span class="hl opt">(</span>options_<span class="hl opt">[</span>OptStream<span class="hl opt">]);</span>
	<span class="hl kwb">int</span> ret<span class="hl opt">;</span>

	<span class="hl com">/* Verify roles are supported. */</span>
	<span class="hl kwa">switch</span> <span class="hl opt">(</span>roles<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">()) {</span>
	<span class="hl kwa">case</span> <span class="hl num">1</span><span class="hl opt">:</span>
		<span class="hl kwa">if</span> <span class="hl opt">(</span>roles<span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">] !=</span> <span class="hl kwc">StreamRole</span><span class="hl opt">::</span>Viewfinder<span class="hl opt">) {</span>
			<span class="hl kwd">qWarning</span><span class="hl opt">() &lt;&lt;</span> <span class="hl str">&quot;Only viewfinder supported for single stream&quot;</span><span class="hl opt">;</span>
			<span class="hl kwa">return</span> <span class="hl opt">-</span>EINVAL<span class="hl opt">;</span>
		<span class="hl opt">}</span>
		<span class="hl kwa">break</span><span class="hl opt">;</span>
	<span class="hl kwa">case</span> <span class="hl num">2</span><span class="hl opt">:</span>
		<span class="hl kwa">if</span> <span class="hl opt">(</span>roles<span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">] !=</span> <span class="hl kwc">StreamRole</span><span class="hl opt">::</span>Viewfinder <span class="hl opt">||